summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp61
-rw-r--r--apct-tests/perftests/core/AndroidTest.xml5
-rw-r--r--apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java6
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java26
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java47
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java51
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java9
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java158
-rw-r--r--api/current.txt25
-rw-r--r--api/removed.txt5
-rw-r--r--api/system-current.txt17
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java2
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java5
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp36
-rw-r--r--cmds/statsd/src/HashableDimensionKey.h44
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h7
-rw-r--r--cmds/statsd/src/StatsService.cpp7
-rw-r--r--cmds/statsd/src/StatsService.h7
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp40
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp56
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp22
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp64
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h22
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h7
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp167
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp8
-rw-r--r--cmds/statsd/src/state/StateListener.h4
-rw-r--r--cmds/statsd/src/state/StateManager.cpp16
-rw-r--r--cmds/statsd/src/state/StateManager.h26
-rw-r--r--cmds/statsd/src/state/StateTracker.cpp39
-rw-r--r--cmds/statsd/src/state/StateTracker.h10
-rw-r--r--cmds/statsd/src/stats_log_util.cpp22
-rw-r--r--cmds/statsd/src/stats_log_util.h2
-rw-r--r--cmds/statsd/src/statsd_config.proto2
-rw-r--r--cmds/statsd/src/subscriber/IncidentdReporter.cpp12
-rw-r--r--cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp724
-rw-r--r--cmds/statsd/tests/metrics/metrics_test_helper.cpp15
-rw-r--r--cmds/statsd/tests/metrics/metrics_test_helper.h3
-rw-r--r--cmds/statsd/tests/state/StateTracker_test.cpp24
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp28
-rw-r--r--cmds/statsd/tests/statsd_test_util.h7
-rw-r--r--core/java/android/accessibilityservice/AccessibilityGestureEvent.java6
-rw-r--r--core/java/android/animation/ValueAnimator.java2
-rw-r--r--core/java/android/annotation/UserHandleAware.java49
-rw-r--r--core/java/android/app/Activity.java1
-rw-r--r--core/java/android/app/ActivityManager.java7
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/app/ActivityView.java2
-rw-r--r--core/java/android/app/AppOpsManager.java8
-rw-r--r--core/java/android/app/ContextImpl.java1
-rw-r--r--core/java/android/app/Notification.java8
-rw-r--r--core/java/android/app/StatsManager.java96
-rw-r--r--core/java/android/app/WindowConfiguration.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java16
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/usage/NetworkStatsManager.java1
-rw-r--r--core/java/android/content/ContentResolver.java93
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/ContextWrapper.java1
-rw-r--r--core/java/android/content/IContentService.aidl2
-rw-r--r--core/java/android/content/Intent.java1
-rw-r--r--core/java/android/content/SyncStatusInfo.java56
-rw-r--r--core/java/android/content/pm/ActivityInfo.java1
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java5
-rw-r--r--core/java/android/content/res/Configuration.java12
-rw-r--r--core/java/android/database/sqlite/SQLiteDebug.java16
-rw-r--r--core/java/android/net/NetworkCapabilities.java1
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java3
-rw-r--r--core/java/android/os/Binder.java10
-rwxr-xr-xcore/java/android/os/Build.java10
-rw-r--r--core/java/android/os/GraphicsEnvironment.java25
-rw-r--r--core/java/android/os/IPullAtomCallback.aidl31
-rw-r--r--core/java/android/os/IPullAtomResultReceiver.aidl32
-rw-r--r--core/java/android/os/IStatsCompanionService.aidl5
-rw-r--r--core/java/android/os/IStatsManager.aidl9
-rw-r--r--core/java/android/os/IStatsPullerCallback.aidl1
-rw-r--r--core/java/android/os/MessageQueue.java2
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/os/StrictMode.java2
-rw-r--r--core/java/android/os/UserHandle.java1
-rw-r--r--core/java/android/os/VibrationEffect.java6
-rw-r--r--core/java/android/os/WorkSource.java6
-rw-r--r--core/java/android/os/health/HealthStatsParceler.java5
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl96
-rw-r--r--core/java/android/os/incremental/IIncrementalServiceProxy.aidl37
-rw-r--r--core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl29
-rw-r--r--core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl27
-rw-r--r--core/java/android/os/incremental/NamedParcelFileDescriptor.aidl28
-rw-r--r--core/java/android/os/storage/StorageManager.java10
-rw-r--r--core/java/android/os/storage/StorageVolume.java1
-rw-r--r--core/java/android/os/storage/VolumeInfo.java21
-rw-r--r--core/java/android/provider/CalendarContract.java1
-rw-r--r--core/java/android/provider/ContactsContract.java2
-rw-r--r--core/java/android/provider/MediaStore.java31
-rw-r--r--core/java/android/provider/Settings.java79
-rw-r--r--core/java/android/service/euicc/EuiccService.java37
-rw-r--r--core/java/android/service/incremental/IIncrementalDataLoaderService.aidl34
-rw-r--r--core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl36
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java40
-rwxr-xr-xcore/java/android/util/DisplayMetrics.java7
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/java/android/util/StatsEvent.aidl19
-rw-r--r--core/java/android/util/StatsEvent.java41
-rw-r--r--core/java/android/view/ActionMode.java3
-rw-r--r--core/java/android/view/Choreographer.java4
-rw-r--r--core/java/android/view/Display.java14
-rw-r--r--core/java/android/view/DisplayInfo.java51
-rw-r--r--core/java/android/view/IDisplayWindowListener.aidl40
-rw-r--r--core/java/android/view/IDisplayWindowRotationCallback.aidl29
-rw-r--r--core/java/android/view/IDisplayWindowRotationController.aidl52
-rw-r--r--core/java/android/view/IWindow.aidl4
-rw-r--r--core/java/android/view/IWindowManager.aidl21
-rw-r--r--core/java/android/view/IWindowSession.aidl9
-rw-r--r--core/java/android/view/LayoutInflater.java5
-rw-r--r--core/java/android/view/MotionEvent.java1
-rw-r--r--core/java/android/view/SurfaceControl.java51
-rw-r--r--core/java/android/view/View.java43
-rw-r--r--core/java/android/view/ViewRootImpl.java71
-rw-r--r--core/java/android/view/WindowManager.java5
-rw-r--r--core/java/android/view/WindowlessWindowManager.java6
-rw-r--r--core/java/android/view/textclassifier/TextClassificationSession.java18
-rw-r--r--core/java/android/widget/NumberPicker.java4
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java4
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java26
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java2
-rw-r--r--core/java/com/android/internal/policy/DecorView.java26
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java4
-rw-r--r--core/java/com/android/internal/util/ScreenShapeHelper.java23
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/jni/android_media_AudioSystem.cpp22
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp6
-rw-r--r--core/jni/android_view_SurfaceControl.cpp19
-rw-r--r--core/proto/android/app/settings_enums.proto5
-rw-r--r--core/proto/android/server/activitymanagerservice.proto3
-rw-r--r--core/proto/android/server/syncstorageengine.proto86
-rw-r--r--core/proto/android/server/windowmanagerservice.proto12
-rw-r--r--core/proto/android/service/package.proto3
-rw-r--r--core/proto/android/stats/textclassifier/Android.bp (renamed from tests/WindowManagerStressTest/Android.bp)18
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values-af/strings.xml24
-rw-r--r--core/res/res/values-am/strings.xml24
-rw-r--r--core/res/res/values-ar/strings.xml24
-rw-r--r--core/res/res/values-as/strings.xml18
-rw-r--r--core/res/res/values-az/strings.xml24
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml24
-rw-r--r--core/res/res/values-be/strings.xml24
-rw-r--r--core/res/res/values-bg/strings.xml24
-rw-r--r--core/res/res/values-bn/strings.xml24
-rw-r--r--core/res/res/values-bs/strings.xml24
-rw-r--r--core/res/res/values-ca/strings.xml24
-rw-r--r--core/res/res/values-cs/strings.xml24
-rw-r--r--core/res/res/values-da/strings.xml24
-rw-r--r--core/res/res/values-de/strings.xml18
-rw-r--r--core/res/res/values-el/strings.xml24
-rw-r--r--core/res/res/values-en-rAU/strings.xml18
-rw-r--r--core/res/res/values-en-rCA/strings.xml18
-rw-r--r--core/res/res/values-en-rGB/strings.xml18
-rw-r--r--core/res/res/values-en-rIN/strings.xml18
-rw-r--r--core/res/res/values-en-rXC/strings.xml9
-rw-r--r--core/res/res/values-es-rUS/strings.xml24
-rw-r--r--core/res/res/values-es/strings.xml24
-rw-r--r--core/res/res/values-et/strings.xml24
-rw-r--r--core/res/res/values-eu/strings.xml40
-rw-r--r--core/res/res/values-fa/strings.xml24
-rw-r--r--core/res/res/values-fi/strings.xml24
-rw-r--r--core/res/res/values-fr-rCA/strings.xml24
-rw-r--r--core/res/res/values-fr/strings.xml18
-rw-r--r--core/res/res/values-gl/strings.xml24
-rw-r--r--core/res/res/values-gu/strings.xml24
-rw-r--r--core/res/res/values-hi/strings.xml24
-rw-r--r--core/res/res/values-hr/strings.xml24
-rw-r--r--core/res/res/values-hu/strings.xml24
-rw-r--r--core/res/res/values-hy/strings.xml18
-rw-r--r--core/res/res/values-in/strings.xml24
-rw-r--r--core/res/res/values-is/strings.xml18
-rw-r--r--core/res/res/values-it/strings.xml24
-rw-r--r--core/res/res/values-iw/strings.xml24
-rw-r--r--core/res/res/values-ja/strings.xml24
-rw-r--r--core/res/res/values-ka/strings.xml18
-rw-r--r--core/res/res/values-kk/strings.xml24
-rw-r--r--core/res/res/values-km/strings.xml24
-rw-r--r--core/res/res/values-kn/strings.xml24
-rw-r--r--core/res/res/values-ko/strings.xml24
-rw-r--r--core/res/res/values-ky/strings.xml24
-rw-r--r--core/res/res/values-lo/strings.xml18
-rw-r--r--core/res/res/values-lt/strings.xml24
-rw-r--r--core/res/res/values-lv/strings.xml24
-rw-r--r--core/res/res/values-mk/strings.xml24
-rw-r--r--core/res/res/values-ml/strings.xml24
-rw-r--r--core/res/res/values-mn/strings.xml24
-rw-r--r--core/res/res/values-mr/strings.xml24
-rw-r--r--core/res/res/values-ms/strings.xml24
-rw-r--r--core/res/res/values-my/strings.xml24
-rw-r--r--core/res/res/values-nb/strings.xml24
-rw-r--r--core/res/res/values-ne/strings.xml18
-rw-r--r--core/res/res/values-nl/strings.xml24
-rw-r--r--core/res/res/values-or/strings.xml18
-rw-r--r--core/res/res/values-pa/strings.xml24
-rw-r--r--core/res/res/values-pl/strings.xml24
-rw-r--r--core/res/res/values-pt-rBR/strings.xml24
-rw-r--r--core/res/res/values-pt-rPT/strings.xml24
-rw-r--r--core/res/res/values-pt/strings.xml24
-rw-r--r--core/res/res/values-ro/strings.xml24
-rw-r--r--core/res/res/values-ru/strings.xml24
-rw-r--r--core/res/res/values-si/strings.xml24
-rw-r--r--core/res/res/values-sk/strings.xml24
-rw-r--r--core/res/res/values-sl/strings.xml24
-rw-r--r--core/res/res/values-sq/strings.xml18
-rw-r--r--core/res/res/values-sr/strings.xml24
-rw-r--r--core/res/res/values-sv/strings.xml26
-rw-r--r--core/res/res/values-sw/strings.xml24
-rw-r--r--core/res/res/values-ta/strings.xml24
-rw-r--r--core/res/res/values-te/strings.xml18
-rw-r--r--core/res/res/values-th/strings.xml24
-rw-r--r--core/res/res/values-tl/strings.xml24
-rw-r--r--core/res/res/values-tr/strings.xml24
-rw-r--r--core/res/res/values-uk/strings.xml24
-rw-r--r--core/res/res/values-ur/strings.xml24
-rw-r--r--core/res/res/values-uz/strings.xml24
-rw-r--r--core/res/res/values-vi/strings.xml24
-rw-r--r--core/res/res/values-zh-rCN/strings.xml18
-rw-r--r--core/res/res/values-zh-rHK/strings.xml24
-rw-r--r--core/res/res/values-zh-rTW/strings.xml24
-rw-r--r--core/res/res/values-zu/strings.xml24
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/config_material.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes_material.xml12
-rw-r--r--core/tests/coretests/src/android/os/BuildTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java27
-rw-r--r--data/etc/com.android.settings.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml4
-rw-r--r--data/etc/services.core.protolog.json84
-rw-r--r--keystore/java/android/security/KeyChain.java24
-rw-r--r--keystore/java/android/security/KeyStore.java11
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java14
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java6
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp5
-rw-r--r--libs/services/Android.bp1
-rw-r--r--libs/services/include/android/util/StatsEvent.h43
-rw-r--r--libs/services/src/util/StatsEvent.cpp58
-rw-r--r--location/TEST_MAPPING10
-rw-r--r--location/java/android/location/GnssStatus.java4
-rw-r--r--location/java/android/location/LocationManager.java76
-rw-r--r--media/java/android/media/AudioAttributes.java2
-rw-r--r--media/java/android/media/AudioManager.java63
-rw-r--r--media/java/android/media/AudioSystem.java15
-rw-r--r--media/java/android/media/ExifInterface.java51
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/IMediaRoute2Provider.aidl2
-rw-r--r--media/java/android/media/IMediaRouter2Client.aidl2
-rw-r--r--media/java/android/media/IMediaRouterService.aidl2
-rw-r--r--media/java/android/media/MediaRoute2Info.java2
-rw-r--r--media/java/android/media/MediaRoute2ProviderInfo.java9
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java4
-rw-r--r--media/java/android/media/MediaRouter2.java58
-rw-r--r--media/java/android/media/MediaScannerConnection.java2
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java79
-rw-r--r--media/jni/android_media_MediaDrm.cpp44
-rw-r--r--media/jni/android_media_MediaMetricsJNI.cpp69
-rw-r--r--media/jni/android_media_MediaMetricsJNI.h2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp139
-rw-r--r--media/jni/android_media_tv_Tuner.h17
-rw-r--r--media/lib/tvremote/OWNERS2
-rw-r--r--media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java61
-rw-r--r--media/lib/tvremote/tests/Android.bp15
-rw-r--r--media/lib/tvremote/tests/AndroidManifest.xml (renamed from tests/WindowManagerStressTest/res/values/colors.xml)19
-rw-r--r--media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java86
-rw-r--r--mime/java-res/android.mime.types1
-rw-r--r--native/android/libandroid_net.map.txt20
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java20
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING12
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java11
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java79
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java11
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java89
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java41
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java)76
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java)4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java (renamed from packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java)4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java133
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java18
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java59
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java68
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java36
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java16
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java60
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java62
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java135
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java150
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java123
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java7
-rw-r--r--packages/SystemUI/res/drawable/ic_create_bubble.xml29
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml52
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java (renamed from packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dock/DockManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java88
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java312
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java500
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt260
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java199
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java99
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java217
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java697
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java254
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt318
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java331
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java79
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java16
-rw-r--r--packages/WallpaperBackup/Android.bp24
-rw-r--r--packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java23
-rw-r--r--packages/WallpaperBackup/test/AndroidManifest.xml13
-rw-r--r--packages/WallpaperBackup/test/AndroidTest.xml27
-rw-r--r--packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java143
-rw-r--r--packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java64
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java16
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java138
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java75
-rw-r--r--services/core/java/com/android/server/content/ContentService.java9
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java547
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java4
-rw-r--r--services/core/java/com/android/server/integrity/model/AtomicFormula.java16
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleParseException.java32
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleParser.java4
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleXmlParser.java188
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java5
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java32
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleSerializer.java9
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java133
-rw-r--r--services/core/java/com/android/server/location/TEST_MAPPING10
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java4
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java8
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java163
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java4
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryDatabase.java119
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java15
-rw-r--r--services/core/java/com/android/server/pm/InstallSource.java84
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java108
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java8
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java6
-rw-r--r--services/core/java/com/android/server/policy/LegacyGlobalActions.java2
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java9
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java28
-rw-r--r--services/core/java/com/android/server/stats/ProcfsMemoryUtil.java103
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java383
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java374
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java48
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java113
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java331
-rw-r--r--services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java285
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java99
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java121
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java82
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java20
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java7
-rw-r--r--services/core/java/com/android/server/wm/CircularDisplayMask.java161
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java18
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java57
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java204
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java72
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowListenerController.java75
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java42
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsController.java12
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsPersister.java10
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java52
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java236
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java10
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java54
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java12
-rw-r--r--services/core/java/com/android/server/wm/Session.java14
-rw-r--r--services/core/java/com/android/server/wm/Task.java2759
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskPersister.java28
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java2762
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java23
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotLoader.java18
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java22
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java14
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowFrames.java112
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java199
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java28
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java36
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java82
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java25
-rw-r--r--services/devicepolicy/Android.bp1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java200
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java431
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java298
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java141
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java18
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java67
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java70
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java51
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java106
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java160
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java116
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestIWindow.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java29
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java6
-rw-r--r--telecomm/java/android/telecom/Call.java22
-rw-r--r--telecomm/java/android/telecom/CallScreeningService.java10
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java5
-rw-r--r--telecomm/java/android/telecom/VideoCallImpl.java21
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java9
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java39
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java12
-rw-r--r--test-mock/Android.bp5
-rw-r--r--test-mock/src/android/test/mock/MockContentResolver.java48
-rw-r--r--tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java12
-rw-r--r--tests/WindowManagerStressTest/AndroidManifest.xml34
-rw-r--r--tests/WindowManagerStressTest/res/layout/activity_main.xml38
-rw-r--r--tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 0 bytes
-rw-r--r--tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 0 bytes
-rw-r--r--tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 0 bytes
-rw-r--r--tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 0 bytes
-rw-r--r--tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.pngbin10486 -> 0 bytes
-rw-r--r--tests/WindowManagerStressTest/res/values/dimens.xml19
-rw-r--r--tests/WindowManagerStressTest/res/values/strings.xml19
-rw-r--r--tests/WindowManagerStressTest/res/values/styles.xml23
-rw-r--r--tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java155
-rw-r--r--tests/net/integration/AndroidManifest.xml15
-rw-r--r--tests/net/java/android/net/netlink/InetDiagSocketTest.java22
-rw-r--r--tests/touchlag/Android.bp14
-rw-r--r--tests/touchlag/touchlag.cpp294
-rw-r--r--tools/aapt2/java/ProguardRules.cpp11
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java2
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java11
584 files changed, 17163 insertions, 10229 deletions
diff --git a/Android.bp b/Android.bp
index 7903742a0fbe..5070b5ea2403 100644
--- a/Android.bp
+++ b/Android.bp
@@ -405,6 +405,8 @@ filegroup {
filegroup {
name: "statsd_aidl",
srcs: [
+ "core/java/android/os/IPullAtomCallback.aidl",
+ "core/java/android/os/IPullAtomResultReceiver.aidl",
"core/java/android/os/IStatsCompanionService.aidl",
"core/java/android/os/IStatsManager.aidl",
"core/java/android/os/IStatsPullerCallback.aidl",
@@ -425,6 +427,7 @@ java_library {
name: "framework-minus-apex",
defaults: ["framework-defaults"],
srcs: [":framework-non-updatable-sources"],
+ libs: ["app-compat-annotations"],
installable: true,
javac_shard_size: 150,
required: [
@@ -463,12 +466,14 @@ java_library {
defaults: ["framework-defaults"],
srcs: [":framework-all-sources"],
installable: false,
+ libs: ["app-compat-annotations"],
}
java_library {
name: "framework-annotation-proc",
defaults: ["framework-aidl-export-defaults"],
srcs: [":framework-all-sources"],
+ libs: ["app-compat-annotations"],
installable: false,
plugins: [
"unsupportedappusage-annotation-processor",
@@ -509,6 +514,7 @@ java_library {
java_library {
name: "framework-atb-backward-compatibility",
installable: true,
+ libs: ["app-compat-annotations"],
srcs: [
"core/java/android/content/pm/AndroidTestBaseUpdater.java",
],
@@ -760,6 +766,46 @@ cc_library {
},
}
+filegroup {
+ name: "incremental_aidl",
+ srcs: [
+ "core/java/android/os/incremental/IIncrementalService.aidl",
+ "core/java/android/os/incremental/IIncrementalServiceProxy.aidl",
+ "core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
+ "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
+ "core/java/android/os/incremental/NamedParcelFileDescriptor.aidl",
+ ],
+ path: "core/java",
+}
+
+filegroup {
+ name: "incremental_data_loader_aidl",
+ srcs: [
+ "core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl",
+ "core/java/android/service/incremental/IIncrementalDataLoaderService.aidl",
+ ],
+ path: "core/java",
+}
+
+aidl_interface {
+ name: "libincremental_aidl",
+ srcs: [
+ ":incremental_aidl",
+ ":incremental_data_loader_aidl",
+ ],
+ backend: {
+ java: {
+ sdk_version: "28",
+ },
+ cpp: {
+ enabled: true,
+ },
+ ndk: {
+ enabled: true,
+ },
+ },
+ api_dir: "aidl/incremental",
+}
gensrcs {
name: "gen-platform-proto-constants",
@@ -968,21 +1014,6 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x
"--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
"--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*"
-// http://b/129765390 Rewrite links to "platform" or "technotes" folders
-// which are siblings (and thus outside of) {@docRoot}.
-//
-// We have to escape \ as \\ and $ as $$ here because they get resolved by
-// different layers of the build tooling. The arguments are wrapped in '' so
-// that the shell doesn't add yet another level of escaping.
-metalava_framework_docs_args += " --replace-documentation " +
- // packages whose descendants to apply replacement to (all packages from
- // libcore/ojluni/src/main/java that contribute to documentation).
- "com.sun:java:javax:jdk.net:sun " +
- // regex of the string to replace
- "'(<a\\s+href\\s?=[\\*\\s]*\")(?:(?:\\{@docRoot\\}/\\.\\./)|(?:(?:\\.\\./)+))((?:platform|technotes).+)\">' " +
- // replacement (with $1, $2 backreferences to the regex groups)
- "'$$1https://docs.oracle.com/javase/8/docs/$$2\">' "
-
packages_to_document = [
"android",
"dalvik",
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 1b289130124f..478cfc1fe811 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -25,4 +25,9 @@
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
</test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/CorePerfTests" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
</configuration>
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
index f43bdf8348ea..f32bf9a4b9e6 100644
--- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
@@ -111,11 +111,9 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
private static class RelayoutRunner {
final Rect mOutFrame = new Rect();
- final Rect mOutOverscanInsets = new Rect();
final Rect mOutContentInsets = new Rect();
final Rect mOutVisibleInsets = new Rect();
final Rect mOutStableInsets = new Rect();
- final Rect mOutOutsets = new Rect();
final Rect mOutBackDropFrame = new Rect();
final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
@@ -149,8 +147,8 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase {
while (state.keepRunning()) {
session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
- mOutOverscanInsets, mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
- mOutOutsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
+ mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
+ mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
mOutSurfaceControl, mOutInsetsState);
}
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index 27790e649a26..4ac3adfd19ce 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -44,7 +44,11 @@ import org.junit.Rule;
import org.junit.Test;
@LargeTest
-public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
+public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
+
+ private static final int PROFILED_ITERATIONS = 2;
+
@Rule
public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
@@ -59,10 +63,24 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
sUiAutomation.dropShellPermissionIdentity();
}
+ /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */
+ @Override
+ public void onStart(int iteration) {
+ startProfiling(WindowAddRemovePerfTest.class.getSimpleName()
+ + "_MethodTracing_" + iteration + ".trace");
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ stopProfiling();
+ }
+
@Test
@ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
public void testAddRemoveWindow() throws Throwable {
- new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
+ final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(PROFILED_ITERATIONS, this);
+ new TestWindow().runBenchmark(state);
}
private static class TestWindow extends BaseIWindow {
@@ -70,7 +88,6 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
final Rect mOutFrame = new Rect();
final Rect mOutContentInsets = new Rect();
final Rect mOutStableInsets = new Rect();
- final Rect mOutOutsets = new Rect();
final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
new DisplayCutout.ParcelableWrapper();
final InsetsState mOutInsetsState = new InsetsState();
@@ -92,7 +109,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
long startTime = SystemClock.elapsedRealtimeNanos();
session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
- mOutOutsets, mOutDisplayCutout, inputChannel, mOutInsetsState);
+ mOutDisplayCutout, inputChannel, mOutInsetsState);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
state.addExtraResult("add", elapsedTimeNsOfAdd);
@@ -102,6 +119,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
state.addExtraResult("remove", elapsedTimeNsOfRemove);
elapsedTimeNs = elapsedTimeNsOfAdd + elapsedTimeNsOfRemove;
+ inputChannel.dispose();
}
}
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index 4d278c3c2d9a..62e9ba84530c 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -21,6 +21,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import android.app.Activity;
import android.app.UiAutomation;
import android.content.Intent;
+import android.os.ParcelFileDescriptor;
import android.perftests.utils.PerfTestActivity;
import androidx.test.rule.ActivityTestRule;
@@ -32,6 +33,10 @@ import org.junit.BeforeClass;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class WindowManagerPerfTestBase {
@@ -40,16 +45,54 @@ public class WindowManagerPerfTestBase {
static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
+ /**
+ * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory
+ * is in /data because while enabling method profling of system server, it cannot write the
+ * trace to external storage.
+ */
+ static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests");
+
@BeforeClass
public static void setUpOnce() {
+ if (!BASE_OUT_PATH.exists()) {
+ executeShellCommand("mkdir -p " + BASE_OUT_PATH);
+ }
// In order to be closer to the real use case.
- sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- sUiAutomation.executeShellCommand("wm dismiss-keyguard");
+ executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ executeShellCommand("wm dismiss-keyguard");
getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
/**
+ * Executes shell command with reading the output. It may also used to block until the current
+ * command is completed.
+ */
+ static ByteArrayOutputStream executeShellCommand(String command) {
+ final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand(command);
+ final byte[] buf = new byte[512];
+ final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ int bytesRead;
+ try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ while ((bytesRead = fis.read(buf)) != -1) {
+ bytes.write(buf, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return bytes;
+ }
+
+ /** Starts method tracing on system server. */
+ void startProfiling(String subPath) {
+ executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath));
+ }
+
+ void stopProfiling() {
+ executeShellCommand("am profile stop system");
+ }
+
+ /**
* Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage.
*/
static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index a83254b463f4..b07523976bfe 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -88,6 +88,15 @@ public final class ManualBenchmarkState {
int[] percentiles() default {};
}
+ /** The interface to receive the events of customized iteration. */
+ public interface CustomizedIterationListener {
+ /** The customized iteration starts. */
+ void onStart(int iteration);
+
+ /** The customized iteration finished. */
+ void onFinished(int iteration);
+ }
+
/** It means the entire {@link StatsReport} is not given. */
private static final int DEFAULT_STATS_REPORT = -2;
@@ -105,7 +114,8 @@ public final class ManualBenchmarkState {
private static final int NOT_STARTED = 0; // The benchmark has not started yet.
private static final int WARMUP = 1; // The benchmark is warming up.
private static final int RUNNING = 2; // The benchmark is running.
- private static final int FINISHED = 3; // The benchmark has stopped.
+ private static final int RUNNING_CUSTOMIZED = 3; // Running for customized measurement.
+ private static final int FINISHED = 4; // The benchmark has stopped.
private int mState = NOT_STARTED; // Current benchmark state.
@@ -116,6 +126,14 @@ public final class ManualBenchmarkState {
private int mMaxIterations = 0;
+ /**
+ * Additinal iteration that used to apply customized measurement. The result during these
+ * iterations won't be counted into {@link #mStats}.
+ */
+ private int mMaxCustomizedIterations;
+ private int mCustomizedIterations;
+ private CustomizedIterationListener mCustomizedIterationListener;
+
// Individual duration in nano seconds.
private ArrayList<Long> mResults = new ArrayList<>();
@@ -189,10 +207,25 @@ public final class ManualBenchmarkState {
final boolean keepRunning = mResults.size() < mMaxIterations;
if (!keepRunning) {
mStats = new Stats(mResults);
+ if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) {
+ mState = RUNNING_CUSTOMIZED;
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
+ }
mState = FINISHED;
}
return keepRunning;
}
+ case RUNNING_CUSTOMIZED: {
+ mCustomizedIterationListener.onFinished(mCustomizedIterations);
+ mCustomizedIterations++;
+ if (mCustomizedIterations >= mMaxCustomizedIterations) {
+ mState = FINISHED;
+ return false;
+ }
+ mCustomizedIterationListener.onStart(mCustomizedIterations);
+ return true;
+ }
case FINISHED:
throw new IllegalStateException("The benchmark has finished.");
default:
@@ -210,11 +243,21 @@ public final class ManualBenchmarkState {
}
/**
- * Adds additional result while this benchmark isn't warming up. It is used when a sequence of
- * operations is executed consecutively, the duration of each operation can also be recorded.
+ * This is used to run the benchmark with more information by enabling some debug mechanism but
+ * we don't want to account the special runs (slower) in the stats report.
+ */
+ public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) {
+ mMaxCustomizedIterations = iterations;
+ mCustomizedIterationListener = listener;
+ }
+
+ /**
+ * Adds additional result while this benchmark isn't warming up or running in customized state.
+ * It is used when a sequence of operations is executed consecutively, the duration of each
+ * operation can also be recorded.
*/
public void addExtraResult(String key, long duration) {
- if (isWarmingUp()) {
+ if (isWarmingUp() || mState == RUNNING_CUSTOMIZED) {
return;
}
if (mExtraResults == null) {
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 4e96f5e0a205..593e49490e94 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -57,7 +57,6 @@ import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -2689,12 +2688,10 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
- protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
- @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
- @NonNull String[] args) {
+ protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+ @NonNull FileDescriptor err, @NonNull String[] args) {
return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
- this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
- args);
+ this, in, out, err, args);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index 1e4861a89694..82292cfeea09 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -578,7 +578,7 @@ public class AppIdleHistory {
}
}
} catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "Unable to read app idle file for user " + userId);
+ Slog.e(TAG, "Unable to read app idle file for user " + userId, e);
} finally {
IoUtils.closeQuietly(fis);
}
@@ -608,6 +608,11 @@ public class AppIdleHistory {
final int N = userHistory.size();
for (int i = 0; i < N; i++) {
String packageName = userHistory.keyAt(i);
+ // Skip any unexpected null package names
+ if (packageName == null) {
+ Slog.w(TAG, "Skipping App Idle write for unexpected null package");
+ continue;
+ }
AppUsageHistory history = userHistory.valueAt(i);
xml.startTag(null, TAG_PACKAGE);
xml.attribute(null, ATTR_NAME, packageName);
@@ -641,7 +646,7 @@ public class AppIdleHistory {
appIdleFile.finishWrite(fos);
} catch (Exception e) {
appIdleFile.failWrite(fos);
- Slog.e(TAG, "Error writing app idle file for user " + userId);
+ Slog.e(TAG, "Error writing app idle file for user " + userId, e);
}
}
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 518a29c2017a..5cb9834de130 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -18,7 +18,6 @@ package com.android.server.stats;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
-import static android.os.Process.getPidsForCommands;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
@@ -27,6 +26,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.ProcfsMemoryUtil.forEachPid;
import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
@@ -76,6 +76,7 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.IPullAtomCallback;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
import android.os.IStoraged;
@@ -144,6 +145,8 @@ import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
+import com.google.android.collect.Sets;
+
import libcore.io.IoUtils;
import org.json.JSONArray;
@@ -163,6 +166,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -216,7 +221,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
* <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns
* /system/bin/statsd for the stats daemon.
*/
- private static final String[] MEMORY_INTERESTING_NATIVE_PROCESSES = new String[]{
+ private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet(
"/system/bin/statsd", // Stats daemon.
"/system/bin/surfaceflinger",
"/system/bin/apexd", // APEX daemon.
@@ -239,8 +244,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
"/system/bin/traced_probes", // Perfetto.
"webview_zygote",
"zygote",
- "zygote64",
- };
+ "zygote64");
/**
* Lowest available uid for apps.
*
@@ -270,6 +274,72 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
private final ShutdownEventReceiver mShutdownEventReceiver;
+
+ private static final class PullerKey {
+ private final int mUid;
+ private final int mAtomTag;
+
+ PullerKey(int uid, int atom) {
+ mUid = uid;
+ mAtomTag = atom;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public int getAtom() {
+ return mAtomTag;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUid, mAtomTag);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PullerKey) {
+ PullerKey other = (PullerKey) obj;
+ return this.mUid == other.getUid() && this.mAtomTag == other.getAtom();
+ }
+ return false;
+ }
+ }
+
+ private static final class PullerValue {
+ private final long mCoolDownNs;
+ private final long mTimeoutNs;
+ private int[] mAdditiveFields;
+ private IPullAtomCallback mCallback;
+
+ PullerValue(long coolDownNs, long timeoutNs, int[] additiveFields,
+ IPullAtomCallback callback) {
+ mCoolDownNs = coolDownNs;
+ mTimeoutNs = timeoutNs;
+ mAdditiveFields = additiveFields;
+ mCallback = callback;
+ }
+
+ public long getCoolDownNs() {
+ return mCoolDownNs;
+ }
+
+ public long getTimeoutNs() {
+ return mTimeoutNs;
+ }
+
+ public int[] getAdditiveFields() {
+ return mAdditiveFields;
+ }
+
+ public IPullAtomCallback getCallback() {
+ return mCallback;
+ }
+ }
+
+ private final HashMap<PullerKey, PullerValue> mPullers = new HashMap<>();
+
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private IWifiManager mWifiManager = null;
@@ -321,7 +391,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
- sStatsd = fetchStatsdService();
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
@@ -1220,27 +1289,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
pulledData.add(e);
}
- int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
- for (int pid : pids) {
- final String processName = readCmdlineFromProcfs(pid);
+ forEachPid((pid, cmdLine) -> {
+ if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+ return;
+ }
final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
if (snapshot == null) {
- continue;
+ return;
}
// Sometimes we get here a process that is not included in the whitelist. It comes
// from forking the zygote for an app. We can ignore that sample because this process
// is collected by ProcessMemoryState.
if (isAppUid(snapshot.uid)) {
- continue;
+ return;
}
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
e.writeInt(snapshot.uid);
- e.writeString(processName);
+ e.writeString(cmdLine);
// RSS high-water mark in bytes.
e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L);
e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
pulledData.add(e);
- }
+ });
// Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.
SystemProperties.set("sys.rss_hwm_reset.on", "1");
}
@@ -1267,22 +1337,23 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
pulledData.add(e);
}
- int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
- for (int pid : pids) {
- final String processName = readCmdlineFromProcfs(pid);
+ forEachPid((pid, cmdLine) -> {
+ if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+ return;
+ }
final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
if (snapshot == null) {
- continue;
+ return;
}
// Sometimes we get here a process that is not included in the whitelist. It comes
// from forking the zygote for an app. We can ignore that sample because this process
// is collected by ProcessMemoryState.
if (isAppUid(snapshot.uid)) {
- continue;
+ return;
}
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
e.writeInt(snapshot.uid);
- e.writeString(processName);
+ e.writeString(cmdLine);
e.writeInt(pid);
e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
e.writeInt(snapshot.rssInKilobytes);
@@ -1290,7 +1361,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeInt(snapshot.swapInKilobytes);
e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
pulledData.add(e);
- }
+ });
}
private static boolean isAppUid(int uid) {
@@ -1731,7 +1802,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeString(Build.BRAND);
e.writeString(Build.PRODUCT);
e.writeString(Build.DEVICE);
- e.writeString(Build.VERSION.RELEASE);
+ e.writeString(Build.VERSION.RELEASE_OR_CODENAME);
e.writeString(Build.ID);
e.writeString(Build.VERSION.INCREMENTAL);
e.writeString(Build.TYPE);
@@ -2549,10 +2620,40 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
}
+ @Override
+ public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+ int[] additiveFields, IPullAtomCallback pullerCallback) {
+ synchronized (sStatsdLock) {
+ // Always cache the puller in SCS.
+ // If statsd is down, we will register it when it comes back up.
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ PullerKey key = new PullerKey(callingUid, atomTag);
+ PullerValue val = new PullerValue(
+ coolDownNs, timeoutNs, additiveFields, pullerCallback);
+ mPullers.put(key, val);
+
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd for registering puller for atom " + atomTag);
+ return;
+ }
+ try {
+ sStatsd.registerPullAtomCallback(
+ callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
// Lifecycle and related code
/**
- * Fetches the statsd IBinder service
+ * Fetches the statsd IBinder service.
+ * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
+ * sStatsd with a null check.
*/
private static IStatsManager fetchStatsdService() {
return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
@@ -2650,6 +2751,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Pull the latest state of UID->app name, version mapping when
// statsd starts.
informAllUidsLocked(mContext);
+ // Register all pullers. If SCS has just started, this should be empty.
+ registerAllPullersLocked();
} finally {
restoreCallingIdentity(token);
}
@@ -2661,10 +2764,21 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ @GuardedBy("sStatsdLock")
+ private void registerAllPullersLocked() throws RemoteException {
+ // TODO: pass in one call, using a file descriptor (similar to uidmap).
+ for (Map.Entry<PullerKey, PullerValue> entry : mPullers.entrySet()) {
+ PullerKey key = entry.getKey();
+ PullerValue val = entry.getValue();
+ sStatsd.registerPullAtomCallback(key.getUid(), key.getAtom(), val.getCoolDownNs(),
+ val.getTimeoutNs(), val.getAdditiveFields(), val.getCallback());
+ }
+ }
+
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
- Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
+ Slog.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
synchronized (sStatsdLock) {
long now = SystemClock.elapsedRealtime();
for (Long timeMillis : mDeathTimeMillis) {
diff --git a/api/current.txt b/api/current.txt
index fad20c14f1cc..0ddc42a38122 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1597,7 +1597,7 @@ package android {
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
- field public static final int windowOverscan = 16843727; // 0x10103cf
+ field @Deprecated public static final int windowOverscan = 16843727; // 0x10103cf
field public static final int windowReenterTransition = 16843951; // 0x10104af
field public static final int windowReturnTransition = 16843950; // 0x10104ae
field public static final int windowSharedElementEnterTransition = 16843833; // 0x1010439
@@ -2333,13 +2333,13 @@ package android {
field public static final int Theme_Material_Light_LightStatusBar = 16974549; // 0x10302d5
field public static final int Theme_Material_Light_NoActionBar = 16974401; // 0x1030241
field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974402; // 0x1030242
- field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
+ field @Deprecated public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974404; // 0x1030244
field public static final int Theme_Material_Light_Panel = 16974405; // 0x1030245
field public static final int Theme_Material_Light_Voice = 16974406; // 0x1030246
field public static final int Theme_Material_NoActionBar = 16974382; // 0x103022e
field public static final int Theme_Material_NoActionBar_Fullscreen = 16974383; // 0x103022f
- field public static final int Theme_Material_NoActionBar_Overscan = 16974384; // 0x1030230
+ field @Deprecated public static final int Theme_Material_NoActionBar_Overscan = 16974384; // 0x1030230
field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974385; // 0x1030231
field public static final int Theme_Material_Panel = 16974386; // 0x1030232
field public static final int Theme_Material_Settings = 16974387; // 0x1030233
@@ -9650,8 +9650,9 @@ package android.content {
method public static boolean isSyncPending(android.accounts.Account, String);
method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
- method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
+ method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
+ method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -23164,6 +23165,7 @@ package android.location {
public class LocationManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
@@ -23194,6 +23196,7 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
+ method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
method public void removeTestProvider(@NonNull String);
@@ -23500,6 +23503,7 @@ package android.media {
method @Deprecated public boolean isBluetoothA2dpOn();
method public boolean isBluetoothScoAvailableOffCall();
method public boolean isBluetoothScoOn();
+ method public boolean isCallScreeningModeSupported();
method public static boolean isHapticPlaybackSupported();
method public boolean isMicrophoneMute();
method public boolean isMusicActive();
@@ -23598,6 +23602,7 @@ package android.media {
field public static final int GET_DEVICES_ALL = 3; // 0x3
field public static final int GET_DEVICES_INPUTS = 1; // 0x1
field public static final int GET_DEVICES_OUTPUTS = 2; // 0x2
+ field public static final int MODE_CALL_SCREENING = 4; // 0x4
field public static final int MODE_CURRENT = -1; // 0xffffffff
field public static final int MODE_INVALID = -2; // 0xfffffffe
field public static final int MODE_IN_CALL = 2; // 0x2
@@ -24149,6 +24154,9 @@ package android.media {
field public static final String TAG_MODEL = "Model";
field public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
field public static final String TAG_OECF = "OECF";
+ field public static final String TAG_OFFSET_TIME = "OffsetTime";
+ field public static final String TAG_OFFSET_TIME_DIGITIZED = "OffsetTimeDigitized";
+ field public static final String TAG_OFFSET_TIME_ORIGINAL = "OffsetTimeOriginal";
field public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame";
field public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
field public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
@@ -34385,6 +34393,7 @@ package android.os {
field public static final String INCREMENTAL;
field public static final int PREVIEW_SDK_INT;
field public static final String RELEASE;
+ field @NonNull public static final String RELEASE_OR_CODENAME;
field @Deprecated public static final String SDK;
field public static final int SDK_INT;
field public static final String SECURITY_PATCH;
@@ -38958,6 +38967,7 @@ package android.provider {
field public static final String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
field public static final String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
field public static final String ACTION_NOTIFICATION_ASSISTANT_SETTINGS = "android.settings.NOTIFICATION_ASSISTANT_SETTINGS";
+ field public static final String ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS = "android.settings.NOTIFICATION_LISTENER_DETAIL_SETTINGS";
field public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -38997,6 +39007,7 @@ package android.provider {
field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
@@ -45354,8 +45365,8 @@ package android.telephony {
method @Nullable public CharSequence getSimSpecificCarrierIdName();
method public int getSimState();
method public int getSimState(int);
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubIdForPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle);
method public int getSupportedModemCount();
method @Nullable public String getTypeAllocationCode();
method @Nullable public String getTypeAllocationCode(int);
@@ -45768,11 +45779,13 @@ package android.telephony.euicc {
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
+ field public static final String ACTION_START_EUICC_ACTIVATION = "android.telephony.euicc.action.START_EUICC_ACTIVATION";
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+ field public static final String EXTRA_USE_QR_SCANNER = "android.telephony.euicc.extra.USE_QR_SCANNER";
field public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
}
@@ -52270,7 +52283,7 @@ package android.view {
field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
- field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
+ field @Deprecated public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
field public static final int FLAG_LOCAL_FOCUS_MODE = 268435456; // 0x10000000
diff --git a/api/removed.txt b/api/removed.txt
index c348ed910bc6..e0e26f7d65a7 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -217,11 +217,6 @@ package android.location {
method @Deprecated public void removeVerticalAccuracy();
}
- public class LocationManager {
- method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
- method @Deprecated public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
- }
-
}
package android.media {
diff --git a/api/system-current.txt b/api/system-current.txt
index d5f544c5757a..636c556e9a7b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6410,6 +6410,10 @@ package android.provider {
package android.security.keystore {
+ public class AndroidKeyStoreProvider extends java.security.Provider {
+ method @NonNull public static java.security.KeyStore getKeyStoreForUid(int) throws java.security.KeyStoreException, java.security.NoSuchProviderException;
+ }
+
public abstract class AttestationUtils {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
field public static final int ID_TYPE_IMEI = 2; // 0x2
@@ -6423,6 +6427,10 @@ package android.security.keystore {
ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
}
+ public static final class KeyGenParameterSpec.Builder {
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
+ }
+
}
package android.security.keystore.recovery {
@@ -6812,7 +6820,7 @@ package android.service.euicc {
method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
method @Deprecated public abstract int onEraseSubscriptions(int);
- method public int onEraseSubscriptionsWithOptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
+ method public int onEraseSubscriptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
method public abstract String onGetEid(int);
@@ -6832,6 +6840,8 @@ package android.service.euicc {
field public static final String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
field public static final String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
field public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
+ field public static final String ACTION_START_CARRIER_ACTIVATION = "android.service.euicc.action.START_CARRIER_ACTIVATION";
+ field public static final String ACTION_START_EUICC_ACTIVATION = "android.service.euicc.action.START_EUICC_ACTIVATION";
field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
field public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
field public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
@@ -8941,7 +8951,7 @@ package android.telephony.euicc {
public class EuiccManager {
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptionsWithOptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
@@ -8964,6 +8974,7 @@ package android.telephony.euicc {
field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
+ field public static final String EXTRA_PHYSICAL_SLOT_ID = "android.telephony.euicc.extra.PHYSICAL_SLOT_ID";
field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
}
@@ -9216,7 +9227,7 @@ package android.telephony.ims {
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
diff --git a/api/test-current.txt b/api/test-current.txt
index 35b1757dae17..44f736ca918a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -717,6 +717,7 @@ package android.content {
}
public class Intent implements java.lang.Cloneable android.os.Parcelable {
+ field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
}
@@ -3358,7 +3359,7 @@ package android.telephony.ims {
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 41d546f6d603..22e1d0187f01 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,6 +174,8 @@ public class Am extends BaseCommand {
instrument.noWindowAnimation = true;
} else if (opt.equals("--no-hidden-api-checks")) {
instrument.disableHiddenApiChecks = true;
+ } else if (opt.equals("--no-test-api-checks")) {
+ instrument.disableTestApiChecks = true;
} else if (opt.equals("--no-isolated-storage")) {
instrument.disableIsolatedStorage = true;
} else if (opt.equals("--user")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 4d7b5a79b4f7..6afd7c40c1c1 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -17,6 +17,7 @@
package com.android.commands.am;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
import android.app.IActivityManager;
@@ -85,6 +86,7 @@ public class Instrument {
String logPath = null;
public boolean noWindowAnimation = false;
public boolean disableHiddenApiChecks = false;
+ public boolean disableTestApiChecks = false;
public boolean disableIsolatedStorage = false;
public String abi = null;
public int userId = UserHandle.USER_CURRENT;
@@ -506,6 +508,9 @@ public class Instrument {
if (disableHiddenApiChecks) {
flags |= INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
}
+ if (disableTestApiChecks) {
+ flags |= INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+ }
if (disableIsolatedStorage) {
flags |= INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
}
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 5e156bb26caa..f9f11b267d5e 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -59,10 +59,11 @@ android::hash_t hashDimension(const HashableDimensionKey& value) {
return JenkinsHashWhiten(hash);
}
-bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values, Value* output) {
+bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values,
+ FieldValue* output) {
for (const auto& value : values) {
if (value.mField.matches(matcherField)) {
- (*output) = value.mValue;
+ (*output) = value;
return true;
}
}
@@ -106,15 +107,34 @@ void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
size_t count = conditionDimension->getValues().size();
if (count != links.conditionFields.size()) {
- // ALOGE("WTF condition link is bad");
return;
}
for (size_t i = 0; i < count; i++) {
conditionDimension->mutableValue(i)->mField.setField(
- links.conditionFields[i].mMatcher.getField());
+ links.conditionFields[i].mMatcher.getField());
conditionDimension->mutableValue(i)->mField.setTag(
- links.conditionFields[i].mMatcher.getTag());
+ links.conditionFields[i].mMatcher.getTag());
+ }
+}
+
+void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
+ HashableDimensionKey* statePrimaryKey) {
+ // First, get the dimension from the event using the "what" fields from the
+ // MetricStateLinks.
+ filterValues(link.metricFields, eventValues, statePrimaryKey);
+
+ // Then check that the statePrimaryKey size equals the number of state fields
+ size_t count = statePrimaryKey->getValues().size();
+ if (count != link.stateFields.size()) {
+ return;
+ }
+
+ // For each dimension Value in the statePrimaryKey, set the field and tag
+ // using the state atom fields from MetricStateLinks.
+ for (size_t i = 0; i < count; i++) {
+ statePrimaryKey->mutableValue(i)->mField.setField(link.stateFields[i].mMatcher.getField());
+ statePrimaryKey->mutableValue(i)->mField.setTag(link.stateFields[i].mMatcher.getTag());
}
}
@@ -185,11 +205,11 @@ string HashableDimensionKey::toString() const {
bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
- mDimensionKeyInCondition == that.getDimensionKeyInCondition();
+ mStateValuesKey == that.getStateValuesKey();
};
string MetricDimensionKey::toString() const {
- return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString();
+ return mDimensionKeyInWhat.toString() + mStateValuesKey.toString();
}
bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
@@ -199,7 +219,7 @@ bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
return false;
}
- return mDimensionKeyInCondition < that.getDimensionKeyInCondition();
+ return mStateValuesKey < that.getStateValuesKey();
}
} // namespace statsd
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index a12385057585..b9b86ce13c8b 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -34,6 +34,12 @@ struct Metric2Condition {
std::vector<Matcher> conditionFields;
};
+struct Metric2State {
+ int32_t stateAtomId;
+ std::vector<Matcher> metricFields;
+ std::vector<Matcher> stateFields;
+};
+
class HashableDimensionKey {
public:
explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
@@ -76,17 +82,16 @@ private:
};
class MetricDimensionKey {
- public:
+public:
explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
- const HashableDimensionKey& dimensionKeyInCondition)
- : mDimensionKeyInWhat(dimensionKeyInWhat),
- mDimensionKeyInCondition(dimensionKeyInCondition) {};
+ const HashableDimensionKey& stateValuesKey)
+ : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){};
MetricDimensionKey(){};
MetricDimensionKey(const MetricDimensionKey& that)
: mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
- mDimensionKeyInCondition(that.getDimensionKeyInCondition()) {};
+ mStateValuesKey(that.getStateValuesKey()){};
MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;
@@ -96,25 +101,25 @@ class MetricDimensionKey {
return mDimensionKeyInWhat;
}
- inline const HashableDimensionKey& getDimensionKeyInCondition() const {
- return mDimensionKeyInCondition;
+ inline const HashableDimensionKey& getStateValuesKey() const {
+ return mStateValuesKey;
}
- inline void setDimensionKeyInCondition(const HashableDimensionKey& key) {
- mDimensionKeyInCondition = key;
+ inline void setStateValuesKey(const HashableDimensionKey& key) {
+ mStateValuesKey = key;
}
- bool hasDimensionKeyInCondition() const {
- return mDimensionKeyInCondition.getValues().size() > 0;
+ bool hasStateValuesKey() const {
+ return mStateValuesKey.getValues().size() > 0;
}
bool operator==(const MetricDimensionKey& that) const;
bool operator<(const MetricDimensionKey& that) const;
- private:
- HashableDimensionKey mDimensionKeyInWhat;
- HashableDimensionKey mDimensionKeyInCondition;
+private:
+ HashableDimensionKey mDimensionKeyInWhat;
+ HashableDimensionKey mStateValuesKey;
};
android::hash_t hashDimension(const HashableDimensionKey& key);
@@ -124,7 +129,7 @@ android::hash_t hashDimension(const HashableDimensionKey& key);
* The value of the FieldValue is output.
*/
bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
- Value* output);
+ FieldValue* output);
/**
* Creating HashableDimensionKeys from FieldValues using matcher.
@@ -152,6 +157,13 @@ void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
const Metric2Condition& links,
HashableDimensionKey* conditionDimension);
+/**
+ * Get dimension values using metric's "what" fields and fill statePrimaryKey's
+ * mField information using "state" fields.
+ */
+void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
+ HashableDimensionKey* statePrimaryKey);
+
} // namespace statsd
} // namespace os
} // namespace android
@@ -172,7 +184,7 @@ template <>
struct hash<MetricDimensionKey> {
std::size_t operator()(const MetricDimensionKey& key) const {
android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
- hash = android::JenkinsHashMix(hash, hashDimension(key.getDimensionKeyInCondition()));
+ hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
return android::JenkinsHashWhiten(hash);
}
};
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 17f27708bf5b..b41771decc7b 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -263,9 +263,10 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
- FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+ FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b665a8b99fbd..f072c9c7b121 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1289,6 +1289,13 @@ Status StatsService::registerPullerCallback(int32_t atomTag,
return Status::ok();
}
+Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
+ int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+ const sp<android::os::IPullAtomCallback>& pullerCallback) {
+ VLOG("StatsService::registerPuller called.");
+ return Status::ok();
+}
+
Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 949094871936..6d40007826e7 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -180,6 +180,13 @@ public:
const String16& packageName) override;
/**
+ * Binder call to register a callback function for a pulled atom.
+ */
+ virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
+ int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+ const sp<android::os::IPullAtomCallback>& pullerCallback) override;
+
+ /**
* Binder call to unregister any existing callback function for a vendor pulled atom.
*/
virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 4a06387e357f..c29b32c5d1c0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -57,10 +57,9 @@ const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DATA = 1;
// for CountMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
+const int FIELD_ID_SLICE_BY_STATE = 6;
const int FIELD_ID_BUCKET_INFO = 3;
const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for CountBucketInfo
const int FIELD_ID_COUNT = 3;
const int FIELD_ID_BUCKET_NUM = 4;
@@ -102,7 +101,13 @@ CountMetricProducer::CountMetricProducer(
mConditionSliced = true;
}
- // TODO(tsaichristine): b/142124705 handle metric state links
+ for (const auto& stateLink : metric.state_link()) {
+ Metric2State ms;
+ ms.stateAtomId = stateLink.state_atom_id();
+ translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
+ translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
+ mMetric2StateLinks.push_back(ms);
+ }
flushIfNeededLocked(startTimeNs);
// Adjust start for partial bucket
@@ -132,10 +137,9 @@ void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
(unsigned long)mCurrentSlicedCounter->size());
if (verbose) {
for (const auto& it : *mCurrentSlicedCounter) {
- fprintf(out, "\t(what)%s\t(condition)%s %lld\n",
- it.first.getDimensionKeyInWhat().toString().c_str(),
- it.first.getDimensionKeyInCondition().toString().c_str(),
- (unsigned long long)it.second);
+ fprintf(out, "\t(what)%s\t(state)%s %lld\n",
+ it.first.getDimensionKeyInWhat().toString().c_str(),
+ it.first.getStateValuesKey().toString().c_str(), (unsigned long long)it.second);
}
}
}
@@ -196,22 +200,16 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
protoOutput->end(dimensionToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
- str_set, protoOutput);
- protoOutput->end(dimensionInConditionToken);
- }
} else {
writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
- FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
- str_set, protoOutput);
- }
+ }
+ // Then fill slice_by_state.
+ for (auto state : dimensionKey.getStateValuesKey().getValues()) {
+ uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_SLICE_BY_STATE);
+ writeStateToProto(state, protoOutput);
+ protoOutput->end(stateToken);
}
// Then fill bucket_info (CountBucketInfo).
for (const auto& bucket : counter.second) {
@@ -282,7 +280,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked(
int64_t eventTimeNs = event.GetElapsedTimestampNs();
flushIfNeededLocked(eventTimeNs);
- if (condition == false) {
+ if (!condition) {
return;
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 61e0892d50a9..8b17d88e0177 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -52,7 +52,7 @@ public:
virtual ~CountMetricProducer();
- void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
+ void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, int oldState,
int newState) override;
protected:
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index ab2a1c3bd65c..fee5e6e3cb46 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -53,10 +53,8 @@ const int FIELD_ID_IS_ACTIVE = 14;
const int FIELD_ID_DATA = 1;
// for DurationMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for DurationBucketInfo
const int FIELD_ID_DURATION = 3;
const int FIELD_ID_BUCKET_NUM = 4;
@@ -120,9 +118,8 @@ DurationMetricProducer::DurationMetricProducer(
mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
mMetric2ConditionLinks.size() == 1) {
- mHasLinksToAllConditionDimensionsInTracker =
- mWizard->equalOutputDimensions(mConditionTrackerIndex,
- mMetric2ConditionLinks.begin()->conditionFields);
+ mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions(
+ mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields);
}
flushIfNeededLocked(startTimeNs);
// Adjust start for partial bucket
@@ -206,8 +203,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
HashableDimensionKey linkedConditionDimensionKey;
- getDimensionForCondition(whatIt.first.getValues(),
- mMetric2ConditionLinks[0],
+ getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
&linkedConditionDimensionKey);
if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
trueConditionDimensions.end()) {
@@ -222,8 +218,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
if (currentUnSlicedPartCondition) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
HashableDimensionKey linkedConditionDimensionKey;
- getDimensionForCondition(whatIt.first.getValues(),
- mMetric2ConditionLinks[0],
+ getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
&linkedConditionDimensionKey);
if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
dimensionsChangedToTrue->end()) {
@@ -380,22 +375,9 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
protoOutput->end(dimensionToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
- str_set, protoOutput);
- protoOutput->end(dimensionInConditionToken);
- }
} else {
writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
- FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
- str_set, protoOutput);
- }
}
// Then fill bucket_info (DurationBucketInfo).
for (const auto& bucket : pair.second) {
@@ -472,7 +454,7 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
if (verbose) {
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (const auto& slice : whatIt.second) {
- fprintf(out, "\t(what)%s\t(condition)%s\n", whatIt.first.toString().c_str(),
+ fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
slice.first.toString().c_str());
slice.second->dumpStates(out, verbose);
}
@@ -483,8 +465,8 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- auto condIt = whatIt->second.find(newKey.getDimensionKeyInCondition());
- if (condIt != whatIt->second.end()) {
+ auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
+ if (stateIt != whatIt->second.end()) {
return false;
}
if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
@@ -493,8 +475,8 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("DurationMetric %lld dropping data for condition dimension key %s",
- (long long)mMetricId, newKey.getDimensionKeyInCondition().toString().c_str());
+ ALOGE("DurationMetric %lld dropping data for state values key %s",
+ (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
@@ -521,24 +503,24 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
const ConditionKey& conditionKeys,
bool condition, const LogEvent& event) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
- const auto& condKey = eventKey.getDimensionKeyInCondition();
+ const auto& stateKey = eventKey.getStateValuesKey();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+ mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
} else {
- if (whatIt->second.find(condKey) == whatIt->second.end()) {
+ if (whatIt->second.find(stateKey) == whatIt->second.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey);
+ mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
}
}
- auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey);
+ auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
if (mUseWhatDimensionAsInternalDimension) {
it->second->noteStart(whatKey, condition,
event.GetElapsedTimestampNs(), conditionKeys);
@@ -597,8 +579,8 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- condIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
+ for (const auto& stateIt : whatIt->second) {
+ stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
}
}
return;
@@ -611,9 +593,9 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- condIt.second->noteStop(
- internalDimensionKey, event.GetElapsedTimestampNs(), false);
+ for (const auto& stateIt : whatIt->second) {
+ stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
+ false);
}
}
return;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d0f88a867da7..64344e837a51 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -56,10 +56,8 @@ const int FIELD_ID_SKIPPED_START_MILLIS = 3;
const int FIELD_ID_SKIPPED_END_MILLIS = 4;
// for GaugeMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for GaugeBucketInfo
const int FIELD_ID_ATOM = 3;
const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
@@ -166,10 +164,9 @@ void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
(unsigned long)mCurrentSlicedBucket->size());
if (verbose) {
for (const auto& it : *mCurrentSlicedBucket) {
- fprintf(out, "\t(what)%s\t(condition)%s %d atoms\n",
- it.first.getDimensionKeyInWhat().toString().c_str(),
- it.first.getDimensionKeyInCondition().toString().c_str(),
- (int)it.second.size());
+ fprintf(out, "\t(what)%s\t(states)%s %d atoms\n",
+ it.first.getDimensionKeyInWhat().toString().c_str(),
+ it.first.getStateValuesKey().toString().c_str(), (int)it.second.size());
}
}
}
@@ -238,22 +235,9 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
protoOutput->end(dimensionToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
- str_set, protoOutput);
- protoOutput->end(dimensionInConditionToken);
- }
} else {
writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
- FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
- str_set, protoOutput);
- }
}
// Then fill bucket_info (GaugeBucketInfo).
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 2a700efe3d37..2c8f0e3d545f 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -16,8 +16,11 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
+
#include "MetricProducer.h"
+#include "state/StateTracker.h"
+
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_ENUM;
using android::util::FIELD_TYPE_INT32;
@@ -92,9 +95,43 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
condition = mCondition == ConditionState::kTrue;
}
+ // Stores atom id to primary key pairs for each state atom that the metric is
+ // sliced by.
+ std::map<int, HashableDimensionKey> statePrimaryKeys;
+
+ // For states with primary fields, use MetricStateLinks to get the primary
+ // field values from the log event. These values will form a primary key
+ // that will be used to query StateTracker for the correct state value.
+ for (const auto& stateLink : mMetric2StateLinks) {
+ getDimensionForState(event.getValues(), stateLink,
+ &statePrimaryKeys[stateLink.stateAtomId]);
+ }
+
+ // For each sliced state, query StateTracker for the state value using
+ // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
+ //
+ // Expected functionality: for any case where the MetricStateLinks are
+ // initialized incorrectly (ex. # of state links != # of primary fields, no
+ // links are provided for a state with primary fields, links are provided
+ // in the wrong order, etc.), StateTracker will simply return kStateUnknown
+ // when queried using an incorrect key.
+ HashableDimensionKey stateValuesKey;
+ for (auto atomId : mSlicedStateAtoms) {
+ FieldValue value;
+ if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
+ // found a primary key for this state, query using the key
+ getMappedStateValue(atomId, statePrimaryKeys[atomId], &value);
+ } else {
+ // if no MetricStateLinks exist for this state atom,
+ // query using the default dimension key (empty HashableDimensionKey)
+ getMappedStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
+ }
+ stateValuesKey.addValue(value);
+ }
+
HashableDimensionKey dimensionInWhat;
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
- MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
+ MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
onMatchedLogEventInternalLocked(
matcherIndex, metricKey, conditionKey, condition, event);
}
@@ -227,6 +264,31 @@ void MetricProducer::writeActiveMetricToProtoOutputStream(
}
}
+void MetricProducer::getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
+ FieldValue* value) {
+ if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
+ value->mValue = Value(StateTracker::kStateUnknown);
+ ALOGW("StateTracker not found for state atom %d", atomId);
+ return;
+ }
+
+ // check if there is a state map for this atom
+ auto atomIt = mStateGroupMap.find(atomId);
+ if (atomIt == mStateGroupMap.end()) {
+ return;
+ }
+ auto valueIt = atomIt->second.find(value->mValue.int_value);
+ if (valueIt == atomIt->second.end()) {
+ // state map exists, but value was not put in a state group
+ // so set mValue to kStateUnknown
+ // TODO(tsaichristine): handle incomplete state maps
+ value->mValue.setInt(StateTracker::kStateUnknown);
+ } else {
+ // set mValue to group_id
+ value->mValue.setLong(valueIt->second);
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index a72de22bd433..d7cbcc8aa6f5 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -30,6 +30,7 @@
#include "matchers/matcher_util.h"
#include "packages/PackageInfoListener.h"
#include "state/StateListener.h"
+#include "state/StateManager.h"
namespace android {
namespace os {
@@ -340,6 +341,12 @@ protected:
return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
}
+ // Query StateManager for original state value.
+ // If no state map exists for this atom, return the original value.
+ // Otherwise, return the group_id mapped to the atom and original value.
+ void getMappedStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
+ FieldValue* value);
+
const int64_t mMetricId;
const ConfigKey mConfigKey;
@@ -392,14 +399,19 @@ protected:
bool mIsActive;
// The slice_by_state atom ids defined in statsd_config.
- std::vector<int> mSlicedStateAtoms;
+ std::vector<int32_t> mSlicedStateAtoms;
// Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>).
- std::unordered_map<int, std::unordered_map<int, int64_t>> mStateGroupMap;
+ std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
+
+ // MetricStateLinks defined in statsd_config that link fields in the state
+ // atom to fields in the "what" atom.
+ std::vector<Metric2State> mMetric2StateLinks;
- FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+ FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d184121f5ba0..286610ae1f48 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -282,9 +282,10 @@ private:
TestActivationOnBootMultipleActivationsDifferentActivationTypes);
FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
- FRIEND_TEST(CountMetricE2eTest, TestWithSimpleState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMappedState);
- FRIEND_TEST(CountMetricE2eTest, TestWithMultipleStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
+ FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
+ FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 0ee156b07c55..eb78ebc521e1 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -59,10 +59,8 @@ const int FIELD_ID_SKIPPED_START_MILLIS = 3;
const int FIELD_ID_SKIPPED_END_MILLIS = 4;
// for ValueMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for ValueBucketInfo
const int FIELD_ID_VALUE_INDEX = 1;
const int FIELD_ID_VALUE_LONG = 2;
@@ -129,6 +127,7 @@ ValueMetricProducer::ValueMetricProducer(
if (metric.has_dimensions_in_what()) {
translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
}
if (metric.links().size() > 0) {
@@ -142,8 +141,6 @@ ValueMetricProducer::ValueMetricProducer(
mConditionSliced = true;
}
- mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-
int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
mCurrentBucketNum += numBucketsForward;
@@ -267,21 +264,9 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
protoOutput->end(dimensionToken);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken =
- protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set,
- protoOutput);
- protoOutput->end(dimensionInConditionToken);
- }
} else {
writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
- FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set,
- protoOutput);
- }
}
// Then fill bucket_info (ValueBucketInfo).
@@ -366,7 +351,7 @@ void ValueMetricProducer::resetBase() {
// - ConditionTimer tracks changes based on AND of condition and active state.
void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
bool isEventTooLate = eventTimeNs < mCurrentBucketStartTimeNs;
- if (ConditionState::kTrue == mCondition && isEventTooLate) {
+ if (isEventTooLate) {
// Drop bucket because event arrived too late, ie. we are missing data for this bucket.
invalidateCurrentBucket();
}
@@ -401,53 +386,61 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
ConditionState newCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
bool isEventTooLate = eventTimeNs < mCurrentBucketStartTimeNs;
- if (mIsActive) {
- if (isEventTooLate) {
- VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
- (long long)mCurrentBucketStartTimeNs);
- StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
- invalidateCurrentBucket();
- } else {
- if (mCondition == ConditionState::kUnknown) {
- // If the condition was unknown, we mark the bucket as invalid since the bucket will
- // contain partial data. For instance, the condition change might happen close to
- // the end of the bucket and we might miss lots of data.
- //
- // We still want to pull to set the base.
- invalidateCurrentBucket();
- }
+ // If the config is not active, skip the event.
+ if (!mIsActive) {
+ mCondition = isEventTooLate ? ConditionState::kUnknown : newCondition;
+ return;
+ }
- // Pull on condition changes.
- bool conditionChanged =
- (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)
- || (mCondition == ConditionState::kFalse &&
- newCondition == ConditionState::kTrue);
- // We do not need to pull when we go from unknown to false.
- //
- // We also pull if the condition was already true in order to be able to flush the
- // bucket at the end if needed.
- //
- // onConditionChangedLocked might happen on bucket boundaries if this is called before
- // #onDataPulled.
- if (mIsPulled && (conditionChanged || condition)) {
- pullAndMatchEventsLocked(eventTimeNs, newCondition);
- }
+ // If the event arrived late, mark the bucket as invalid and skip the event.
+ if (isEventTooLate) {
+ VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+ (long long)mCurrentBucketStartTimeNs);
+ StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
+ invalidateCurrentBucket();
+ mCondition = ConditionState::kUnknown;
+ mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+ return;
+ }
- // When condition change from true to false, clear diff base but don't
- // reset other counters as we may accumulate more value in the bucket.
- if (mUseDiff && mCondition == ConditionState::kTrue
- && newCondition == ConditionState::kFalse) {
- resetBase();
- }
- }
+ // If the previous condition was unknown, mark the bucket as invalid
+ // because the bucket will contain partial data. For example, the condition
+ // change might happen close to the end of the bucket and we might miss a
+ // lot of data.
+ //
+ // We still want to pull to set the base.
+ if (mCondition == ConditionState::kUnknown) {
+ invalidateCurrentBucket();
}
- mCondition = isEventTooLate ? initialCondition(mConditionTrackerIndex) : newCondition;
+ // Pull and match for the following condition change cases:
+ // unknown/false -> true - condition changed
+ // true -> false - condition changed
+ // true -> true - old condition was true so we can flush the bucket at the
+ // end if needed.
+ //
+ // We don’t need to pull for unknown -> false or false -> false.
+ //
+ // onConditionChangedLocked might happen on bucket boundaries if this is
+ // called before #onDataPulled.
+ if (mIsPulled &&
+ (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) {
+ pullAndMatchEventsLocked(eventTimeNs, newCondition);
+ }
- if (mIsActive) {
- flushIfNeededLocked(eventTimeNs);
- mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+ // For metrics that use diff, when condition changes from true to false,
+ // clear diff base but don't reset other counts because we may accumulate
+ // more value in the bucket.
+ if (mUseDiff &&
+ (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)) {
+ resetBase();
}
+
+ // Update condition state after pulling.
+ mCondition = newCondition;
+
+ flushIfNeededLocked(eventTimeNs);
+ mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
}
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs,
@@ -472,33 +465,33 @@ int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTime
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
bool pullSuccess, int64_t originalPullTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mCondition == ConditionState::kTrue) {
- // If the pull failed, we won't be able to compute a diff.
- if (!pullSuccess) {
- invalidateCurrentBucket();
+ if (mCondition == ConditionState::kTrue) {
+ // If the pull failed, we won't be able to compute a diff.
+ if (!pullSuccess) {
+ invalidateCurrentBucket();
+ } else {
+ bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
+ if (isEventLate) {
+ // If the event is late, we are in the middle of a bucket. Just
+ // process the data without trying to snap the data to the nearest bucket.
+ accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
} else {
- bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
- if (isEventLate) {
- // If the event is late, we are in the middle of a bucket. Just
- // process the data without trying to snap the data to the nearest bucket.
- accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
- } else {
- // For scheduled pulled data, the effective event time is snap to the nearest
- // bucket end. In the case of waking up from a deep sleep state, we will
- // attribute to the previous bucket end. If the sleep was long but not very
- // long, we will be in the immediate next bucket. Previous bucket may get a
- // larger number as we pull at a later time than real bucket end.
- //
- // If the sleep was very long, we skip more than one bucket before sleep. In
- // this case, if the diff base will be cleared and this new data will serve as
- // new diff base.
- int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
- StatsdStats::getInstance().noteBucketBoundaryDelayNs(
- mMetricId, originalPullTimeNs - bucketEndTime);
- accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
- }
+ // For scheduled pulled data, the effective event time is snap to the nearest
+ // bucket end. In the case of waking up from a deep sleep state, we will
+ // attribute to the previous bucket end. If the sleep was long but not very
+ // long, we will be in the immediate next bucket. Previous bucket may get a
+ // larger number as we pull at a later time than real bucket end.
+ //
+ // If the sleep was very long, we skip more than one bucket before sleep. In
+ // this case, if the diff base will be cleared and this new data will serve as
+ // new diff base.
+ int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
+ StatsdStats::getInstance().noteBucketBoundaryDelayNs(
+ mMetricId, originalPullTimeNs - bucketEndTime);
+ accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
}
}
+ }
// We can probably flush the bucket. Since we used bucketEndTime when calling
// #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
@@ -579,10 +572,10 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
if (verbose) {
for (const auto& it : mCurrentSlicedBucket) {
for (const auto& interval : it.second) {
- fprintf(out, "\t(what)%s\t(condition)%s (value)%s\n",
- it.first.getDimensionKeyInWhat().toString().c_str(),
- it.first.getDimensionKeyInCondition().toString().c_str(),
- interval.value.toString().c_str());
+ fprintf(out, "\t(what)%s\t(states)%s (value)%s\n",
+ it.first.getDimensionKeyInWhat().toString().c_str(),
+ it.first.getStateValuesKey().toString().c_str(),
+ interval.value.toString().c_str());
}
}
}
@@ -821,7 +814,7 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
if (eventTimeNs < currentBucketEndTimeNs) {
- VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+ VLOG("eventTime is %lld, less than current bucket end time %lld", (long long)eventTimeNs,
(long long)(currentBucketEndTimeNs));
return;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 33e162ec2d24..6e767175caba 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -472,11 +472,13 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
return false;
}
+ } else {
+ if (metric.state_link_size() > 0) {
+ ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state");
+ return false;
+ }
}
- // TODO(tsaichristine): add check for unequal number of MetricStateLinks
- // and slice_by_states
-
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
bool success = handleMetricActivation(config, metric.id(), metricIndex,
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
index a31690a102ed..f2b9a6b9b89f 100644
--- a/cmds/statsd/src/state/StateListener.h
+++ b/cmds/statsd/src/state/StateListener.h
@@ -43,8 +43,8 @@ public:
* [oldState]: Previous state value before state change
* [newState]: Current state value after state change
*/
- virtual void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
- int newState) = 0;
+ virtual void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey,
+ int oldState, int newState) = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
index 95b2c7691803..2fa28c9846fd 100644
--- a/cmds/statsd/src/state/StateManager.cpp
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -35,7 +35,7 @@ void StateManager::onLogEvent(const LogEvent& event) {
}
}
-bool StateManager::registerListener(int atomId, wp<StateListener> listener) {
+bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) {
std::lock_guard<std::mutex> lock(mMutex);
// Check if state tracker already exists
@@ -53,7 +53,7 @@ bool StateManager::registerListener(int atomId, wp<StateListener> listener) {
return true;
}
-void StateManager::unregisterListener(int atomId, wp<StateListener> listener) {
+void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener) {
std::unique_lock<std::mutex> lock(mMutex);
// Hold the sp<> until the lock is released so that ~StateTracker() is
@@ -77,13 +77,15 @@ void StateManager::unregisterListener(int atomId, wp<StateListener> listener) {
lock.unlock();
}
-int StateManager::getStateValue(int atomId, const HashableDimensionKey& key) {
+bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key,
+ FieldValue* output) const {
std::lock_guard<std::mutex> lock(mMutex);
- if (mStateTrackers.find(atomId) != mStateTrackers.end()) {
- return mStateTrackers[atomId]->getStateValue(key);
- }
- return StateTracker::kStateUnknown;
+ auto it = mStateTrackers.find(atomId);
+ if (it != mStateTrackers.end()) {
+ return it->second->getStateValue(key, output);
+ }
+ return false;
}
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index 89ee6c04b922..272724ceeb08 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -42,26 +42,30 @@ public:
// Returns true if atomId is being tracked and is associated with a state
// atom. StateManager notifies the correct StateTracker to register listener.
// If the correct StateTracker does not exist, a new StateTracker is created.
- bool registerListener(int atomId, wp<StateListener> listener);
+ bool registerListener(int32_t atomId, wp<StateListener> listener);
// Notifies the correct StateTracker to unregister a listener
// and removes the tracker if it no longer has any listeners.
- void unregisterListener(int atomId, wp<StateListener> listener);
+ void unregisterListener(int32_t atomId, wp<StateListener> listener);
- // Queries the correct StateTracker for the original/un-mapped state value
- // that is mapped to the given query key.
- // If the StateTracker doesn't exist, returns StateTracker::kStateUnknown.
- int getStateValue(int atomId, const HashableDimensionKey& queryKey);
+ // Returns true if the StateTracker exists and queries for the
+ // original state value mapped to the given query key. The state value is
+ // stored and output in a FieldValue class.
+ // Returns false if the StateTracker doesn't exist.
+ bool getStateValue(int32_t atomId, const HashableDimensionKey& queryKey,
+ FieldValue* output) const;
- inline int getStateTrackersCount() {
+ inline int getStateTrackersCount() const {
std::lock_guard<std::mutex> lock(mMutex);
return mStateTrackers.size();
}
- inline int getListenersCount(int atomId) {
+ inline int getListenersCount(int32_t atomId) const {
std::lock_guard<std::mutex> lock(mMutex);
- if (mStateTrackers.find(atomId) != mStateTrackers.end()) {
- return mStateTrackers[atomId]->getListenersCount();
+
+ auto it = mStateTrackers.find(atomId);
+ if (it != mStateTrackers.end()) {
+ return it->second->getListenersCount();
}
return -1;
}
@@ -70,7 +74,7 @@ private:
mutable std::mutex mMutex;
// Maps state atom ids to StateTrackers
- std::unordered_map<int, sp<StateTracker>> mStateTrackers;
+ std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers;
};
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index 323fc0e94ab2..e6f61226018e 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -25,10 +25,8 @@ namespace android {
namespace os {
namespace statsd {
-StateTracker::StateTracker(const int atomId,
- const util::StateAtomFieldOptions& stateAtomInfo)
- : mAtomId(atomId),
- mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
+StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo)
+ : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
// create matcher for each primary field
// TODO(tsaichristine): b/142108433 handle when primary field is first uid in chain
for (const auto& primary : stateAtomInfo.primaryFields) {
@@ -55,24 +53,26 @@ void StateTracker::onLogEvent(const LogEvent& event) {
}
// parse event for state value
- Value state;
- int32_t stateValue;
- if (!filterValues(mStateField, event.getValues(), &state) || state.getType() != INT) {
- ALOGE("StateTracker error extracting state from log event. Type: %d", state.getType());
+ FieldValue stateValue;
+ int32_t state;
+ if (!filterValues(mStateField, event.getValues(), &stateValue) ||
+ stateValue.mValue.getType() != INT) {
+ ALOGE("StateTracker error extracting state from log event. Type: %d",
+ stateValue.mValue.getType());
handlePartialReset(primaryKey);
return;
}
- stateValue = state.int_value;
+ state = stateValue.mValue.int_value;
- if (stateValue == mResetState) {
- VLOG("StateTracker Reset state: %s", state.toString().c_str());
+ if (state == mResetState) {
+ VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
handleReset();
}
// track and update state
int32_t oldState = 0;
int32_t newState = 0;
- updateState(primaryKey, stateValue, &oldState, &newState);
+ updateState(primaryKey, state, &oldState, &newState);
// notify all listeners if state has changed
if (oldState != newState) {
@@ -96,18 +96,27 @@ void StateTracker::unregisterListener(wp<StateListener> listener) {
mListeners.erase(listener);
}
-int StateTracker::getStateValue(const HashableDimensionKey& queryKey) const {
+bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
+ output->mField = mStateField.mMatcher;
+
+ // Check that the query key has the correct number of primary fields.
if (queryKey.getValues().size() == mPrimaryFields.size()) {
auto it = mStateMap.find(queryKey);
if (it != mStateMap.end()) {
- return it->second.state;
+ output->mValue = it->second.state;
+ return true;
}
} else if (queryKey.getValues().size() > mPrimaryFields.size()) {
ALOGE("StateTracker query key size > primary key size is illegal");
} else {
ALOGE("StateTracker query key size < primary key size is not supported");
}
- return mDefaultState;
+
+ // Set the state value to unknown if:
+ // - query key size is incorrect
+ // - query key is not found in state map
+ output->mValue = StateTracker::kStateUnknown;
+ return false;
}
void StateTracker::handleReset() {
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index cfa9fd8f6272..450412d4ec3b 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -30,7 +30,7 @@ namespace statsd {
class StateTracker : public virtual RefBase {
public:
- StateTracker(const int atomId, const util::StateAtomFieldOptions& stateAtomInfo);
+ StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo);
virtual ~StateTracker(){};
@@ -45,10 +45,12 @@ public:
void unregisterListener(wp<StateListener> listener);
- // Returns the state value mapped to the given query key.
+ // The output is a FieldValue object that has mStateField as the field and
+ // the original state value (found using the given query key) as the value.
+ //
// If the key isn't mapped to a state or the key size doesn't match the
- // primary key size, the default state is returned.
- int getStateValue(const HashableDimensionKey& queryKey) const;
+ // number of primary fields, the output value is set to kStateUnknown.
+ bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const;
inline int getListenersCount() const {
return mListeners.size();
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index c22e3cc07a3b..76c193679eef 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -53,6 +53,11 @@ const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8;
const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
+// for StateValue Proto
+const int STATE_VALUE_ATOM_ID = 1;
+const int STATE_VALUE_CONTENTS_GROUP_ID = 2;
+const int STATE_VALUE_CONTENTS_VALUE = 3;
+
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
const int FIELD_ID_PULL_ATOM_ID = 1;
@@ -416,6 +421,23 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value
protoOutput->end(atomToken);
}
+void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput) {
+ protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_ATOM_ID, state.mField.getTag());
+
+ switch (state.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_CONTENTS_VALUE,
+ state.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | STATE_VALUE_CONTENTS_GROUP_ID,
+ state.mValue.long_value);
+ break;
+ default:
+ break;
+ }
+}
+
int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index bfb84cf4d1b9..0a86363a7090 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -40,6 +40,8 @@ void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
util::ProtoOutputStream* protoOutput);
+void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput);
+
// Convert the TimeUnit enum to the bucket size in millis with a guardrail on
// bucket size.
int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 0664867aa866..a22805b6b525 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -178,7 +178,7 @@ message MetricConditionLink {
}
message MetricStateLink {
- optional int64 state = 1;
+ optional int32 state_atom_id = 1;
optional FieldMatcher fields_in_what = 2;
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index f2c6f1ad6759..f1320c2f746d 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -52,7 +52,6 @@ const int FIELD_ID_TRIGGER_DETAILS = 4;
const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
-const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION = 3;
const int FIELD_ID_METRIC_VALUE_VALUE = 4;
const int FIELD_ID_PACKAGE_INFO = 3;
@@ -84,10 +83,8 @@ void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensio
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
headerProto.end(dimToken);
+ // deprecated field
// optional DimensionsValue dimension_in_condition = 3;
- dimToken = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), nullptr, &headerProto);
- headerProto.end(dimToken);
// optional int64 value = 4;
headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
@@ -106,13 +103,6 @@ void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensio
}
}
- for (const auto& dim : dimensionKey.getDimensionKeyInCondition().getValues()) {
- int uid = getUidIfExists(dim);
- if (uid > 2000) {
- uids.insert(uid);
- }
- }
-
if (!uids.empty()) {
uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index 6591d69cdc1a..0f51c1b5a4ce 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -18,6 +18,7 @@
#include "src/StatsLogProcessor.h"
#include "src/state/StateManager.h"
+#include "src/state/StateTracker.h"
#include "tests/statsd_test_util.h"
namespace android {
@@ -26,8 +27,20 @@ namespace statsd {
#ifdef __ANDROID__
-TEST(CountMetricE2eTest, TestWithSimpleState) {
- // Initialize config
+const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
+const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
+
+/**
+ * Test a count metric that has one slice_by_state with no primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and no entries in mStateGroupMap.
+
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedState) {
+ // Initialize config.
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
@@ -37,30 +50,22 @@ TEST(CountMetricE2eTest, TestWithSimpleState) {
auto state = CreateScreenState();
*config.add_state() = state;
- // Create count metric that slices by screen state
+ // Create count metric that slices by screen state.
int64_t metricId = 123456;
auto countMetric = config.add_count_metric();
countMetric->set_id(metricId);
countMetric->set_what(syncStartMatcher.id());
- countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
countMetric->add_slice_by_state(state.id());
- // Initialize StatsLogProcessor
- const int64_t baseTimeNs = 0; // 0:00
- const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
- const int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
int uid = 12345;
int64_t cfgId = 98765;
ConfigKey cfgKey(uid, cfgId);
-
- auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
- // Check that StateTrackers were properly initialized.
- EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
- EXPECT_EQ(1,
- StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
// Check that CountMetricProducer was initialized correctly.
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -69,12 +74,118 @@ TEST(CountMetricE2eTest, TestWithSimpleState) {
EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x (syncStartEvents)
+ | | (ScreenIsOnEvent)
+ | | (ScreenIsOffEvent)
+ | (ScreenUnknownEvent)
+ */
+ // Initialize log events - first bucket.
+ int appUid = 123;
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 50 * NS_PER_SEC)); // 1:00
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 75 * NS_PER_SEC)); // 1:25
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 350 * NS_PER_SEC)); // 6:00
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 400 * NS_PER_SEC)); // 6:50
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 475 * NS_PER_SEC)); // 8:05
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+ bucketStartTimeNs + 500 * NS_PER_SEC)); // 8:30
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
}
-TEST(CountMetricE2eTest, TestWithMappedState) {
- // Initialize config
+/**
+ * Test a count metric that has one slice_by_state with a mapping and no
+ * primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
+ *
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
+ // Initialize config.
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
@@ -84,30 +195,26 @@ TEST(CountMetricE2eTest, TestWithMappedState) {
auto state = CreateScreenStateWithOnOffMap();
*config.add_state() = state;
- // Create count metric that slices by screen state with on/off map
+ // Create count metric that slices by screen state with on/off map.
int64_t metricId = 123456;
auto countMetric = config.add_count_metric();
countMetric->set_id(metricId);
countMetric->set_what(syncStartMatcher.id());
- countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
countMetric->add_slice_by_state(state.id());
- // Initialize StatsLogProcessor
- const int64_t baseTimeNs = 0; // 0:00
- const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
- const int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
int uid = 12345;
int64_t cfgId = 98765;
ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
- // Check that StateTrackers were properly initialized.
+ // Check that StateTrackers were initialized correctly.
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
- EXPECT_EQ(1,
- StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
// Check that CountMetricProducer was initialized correctly.
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -116,58 +223,371 @@ TEST(CountMetricE2eTest, TestWithMappedState) {
EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
StateMap map = state.map();
for (auto group : map.group()) {
for (auto value : group.value()) {
- EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value],
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
group.group_id());
}
}
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x x x x (syncStartEvents)
+ -----------------------------------------------------------SCREEN_OFF events
+ | (ScreenStateUnknownEvent = 0)
+ | | (ScreenStateOffEvent = 1)
+ | (ScreenStateDozeEvent = 3)
+ | (ScreenStateDozeSuspendEvent = 4)
+ -----------------------------------------------------------SCREEN_ON events
+ | | (ScreenStateOnEvent = 2)
+ | (ScreenStateVrEvent = 5)
+ | (ScreenStateOnSuspendEvent = 6)
+ */
+ // Initialize log events - first bucket.
+ int appUid = 123;
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+ bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
+ bucketStartTimeNs + 180 * NS_PER_SEC)); // 3:10
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
+ bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
+ bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
+ events.push_back(CreateScreenStateChangedEvent(
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND,
+ bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
+ events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
+ bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(4, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
}
-TEST(CountMetricE2eTest, TestWithMultipleStates) {
- // Initialize config
+/**
+ * Test a count metric that has one slice_by_state with a primary field.
+
+ * Once the CountMetricProducer is initialized, it should have one
+ * MetricStateLink stored. State querying using a non-empty primary key
+ * should also work as intended.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
+ // Initialize config.
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
- auto syncStartMatcher = CreateSyncStartAtomMatcher();
- *config.add_atom_matcher() = syncStartMatcher;
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
+
+ auto state = CreateUidProcessState();
+ *config.add_state() = state;
+
+ // Create count metric that slices by uid process state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+ /*
+ NOTE: "1" or "2" represents the uid associated with the state/app crash event
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10
+ |-----------------------------|-----------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ -----------------------------------------------------------PROCESS STATE events
+ 1 2 (ProcessStateTopEvent = 1002)
+ 1 1 (ProcessStateForegroundServiceEvent = 1003)
+ 2 (ProcessStateImportantBackgroundEvent = 1006)
+ 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
+
+ Based on the diagram above, an AppCrashEvent querying for process state value would return:
+ - StateTracker::kStateUnknown
+ - Important foreground
+ - Top
+ - Important foreground
+ - Foreground service
+ - Top (both the app crash and state still have matching uid = 2)
+
+ - Foreground service
+ - Foreground service
+ - Important background
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+ bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
+ events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+ bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+ bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
+ events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+ bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
auto state1 = CreateScreenStateWithOnOffMap();
*config.add_state() = state1;
auto state2 = CreateUidProcessState();
*config.add_state() = state2;
- // Create count metric that slices by screen state with on/off map
+ // Create count metric that slices by screen state with on/off map and
+ // slices by uid process state.
int64_t metricId = 123456;
auto countMetric = config.add_count_metric();
countMetric->set_id(metricId);
- countMetric->set_what(syncStartMatcher.id());
- countMetric->set_bucket(TimeUnit::ONE_MINUTE);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
countMetric->add_slice_by_state(state1.id());
countMetric->add_slice_by_state(state2.id());
-
- // Initialize StatsLogProcessor
- const int64_t baseTimeNs = 0; // 0:00
- const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
- const int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
int uid = 12345;
int64_t cfgId = 98765;
ConfigKey cfgKey(uid, cfgId);
-
- auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
// Check that StateTrackers were properly initialized.
EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
- EXPECT_EQ(1,
- StateManager::getInstance().getListenersCount(android::util::SCREEN_STATE_CHANGED));
- EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
- android::util::UID_PROCESS_STATE_CHANGED));
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
// Check that CountMetricProducer was initialized correctly.
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
@@ -176,17 +596,205 @@ TEST(CountMetricE2eTest, TestWithMultipleStates) {
EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), android::util::SCREEN_STATE_CHANGED);
- EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), android::util::UID_PROCESS_STATE_CHANGED);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
StateMap map = state1.map();
for (auto group : map.group()) {
for (auto value : group.value()) {
- EXPECT_EQ(metricProducer->mStateGroupMap[android::util::SCREEN_STATE_CHANGED][value],
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
group.group_id());
}
}
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ -----------------------------------------------------------SCREEN_OFF events
+ | (ScreenStateUnknownEvent = 0)
+ | | (ScreenStateOffEvent = 1)
+ | (ScreenStateDozeEvent = 3)
+ -----------------------------------------------------------SCREEN_ON events
+ | | (ScreenStateOnEvent = 2)
+ | (ScreenStateOnSuspendEvent = 6)
+ -----------------------------------------------------------PROCESS STATE events
+ 1 2 (ProcessStateTopEvent = 1002)
+ 1 (ProcessStateForegroundServiceEvent = 1003)
+ 2 (ProcessStateImportantBackgroundEvent = 1006)
+ 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
+
+ Based on the diagram above, Screen State / Process State pairs for each
+ AppCrashEvent are:
+ - StateTracker::kStateUnknown / important foreground
+ - off / important foreground
+ - off / Top
+ - on / important foreground
+ - off / important foreground
+ - off / top
+
+ - off / important foreground
+ - off / foreground service
+ - on / important background
+
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 5 * NS_PER_SEC)); // 0:15
+ events.push_back(
+ CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+ bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 160 * NS_PER_SEC)); // 2:50
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
+ bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
+ bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
+ events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+ bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
+ bucketStartTimeNs + 380 * NS_PER_SEC)); // 6:30
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
+ bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ bucketStartTimeNs + 420 * NS_PER_SEC)); // 7:10
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
+ events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
+ bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
+ events.push_back(CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
+ events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
+ bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1, data.slice_by_state(0).value());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(5);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
index 7b9c0d6ab28e..108df04b45cb 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.cpp
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
@@ -26,10 +26,23 @@ HashableDimensionKey getMockedDimensionKey(int tagId, int key, string value) {
return dimension;
}
+HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value) {
+ HashableDimensionKey dimension;
+ int pos[] = {key, 0, 0};
+ dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value)));
+
+ return dimension;
+}
+
MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, string value) {
return MetricDimensionKey(getMockedDimensionKey(tagId, key, value), DEFAULT_DIMENSION_KEY);
}
+MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value) {
+ return MetricDimensionKey(DEFAULT_DIMENSION_KEY,
+ getMockedDimensionKeyLongValue(tagId, key, value));
+}
+
void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) {
matcher->set_field(tagId);
}
@@ -41,4 +54,4 @@ void buildSimpleAtomFieldMatcher(const int tagId, const int fieldNum, FieldMatch
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 329e39fc4eff..09c4d9e41fc2 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -47,6 +47,9 @@ class MockUidMap : public UidMap {
HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
+HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value);
+MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value);
+
// Utils to build FieldMatcher proto for simple one-depth atoms.
void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher);
void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 8d380006a8ab..4208fef3860e 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -50,6 +50,12 @@ public:
}
};
+int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& queryKey) {
+ FieldValue output;
+ mgr.getStateValue(atomId, queryKey, &output);
+ return output.mValue.int_value;
+}
+
// START: build event functions.
// State with no primary fields - ScreenStateChanged
std::shared_ptr<LogEvent> buildScreenEvent(int state) {
@@ -240,7 +246,7 @@ TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
// check StateTracker was updated by querying for state
HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
- EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, queryKey));
+ EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey));
}
/**
@@ -265,7 +271,7 @@ TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
// check StateTracker was updated by querying for state
HashableDimensionKey queryKey;
getUidProcessKey(1000 /* uid */, &queryKey);
- EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey));
+ EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey));
}
/**
@@ -290,7 +296,7 @@ TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
// check StateTracker was updated by querying for state
HashableDimensionKey queryKey;
getOverlayKey(1000 /* uid */, "package1", &queryKey);
- EXPECT_EQ(1, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey));
+ EXPECT_EQ(1, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey));
}
/**
@@ -353,25 +359,25 @@ TEST(StateTrackerTest, TestStateQuery) {
// Query for UidProcessState of uid 1001
HashableDimensionKey queryKey1;
getUidProcessKey(1001, &queryKey1);
- EXPECT_EQ(1003, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+ EXPECT_EQ(1003, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
// Query for UidProcessState of uid 1004 - not in state map
HashableDimensionKey queryKey2;
getUidProcessKey(1004, &queryKey2);
- EXPECT_EQ(-1, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED,
- queryKey2)); // default state
+ EXPECT_EQ(-1, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED,
+ queryKey2)); // default state
// Query for UidProcessState of uid 1001 - after change in state
mgr.onLogEvent(*event4);
- EXPECT_EQ(1002, mgr.getStateValue(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+ EXPECT_EQ(1002, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
// Query for ScreenState
- EXPECT_EQ(2, mgr.getStateValue(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+ EXPECT_EQ(2, getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
// Query for OverlayState of uid 1000, package name "package2"
HashableDimensionKey queryKey3;
getOverlayKey(1000, "package2", &queryKey3);
- EXPECT_EQ(2, mgr.getStateValue(android::util::OVERLAY_STATE_CHANGED, queryKey3));
+ EXPECT_EQ(2, getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 38c22ab5d253..d154b1b9cad9 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -254,28 +254,28 @@ Predicate CreateIsInBackgroundPredicate() {
State CreateScreenState() {
State state;
state.set_id(StringToId("ScreenState"));
- state.set_atom_id(29);
+ state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
return state;
}
State CreateUidProcessState() {
State state;
state.set_id(StringToId("UidProcessState"));
- state.set_atom_id(27);
+ state.set_atom_id(android::util::UID_PROCESS_STATE_CHANGED);
return state;
}
State CreateOverlayState() {
State state;
state.set_id(StringToId("OverlayState"));
- state.set_atom_id(59);
+ state.set_atom_id(android::util::OVERLAY_STATE_CHANGED);
return state;
}
State CreateScreenStateWithOnOffMap() {
State state;
state.set_id(StringToId("ScreenStateOnOff"));
- state.set_atom_id(29);
+ state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
auto map = CreateScreenStateOnOffMap();
*state.mutable_map() = map;
@@ -286,7 +286,7 @@ State CreateScreenStateWithOnOffMap() {
State CreateScreenStateWithInDozeMap() {
State state;
state.set_id(StringToId("ScreenStateInDoze"));
- state.set_atom_id(29);
+ state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
auto map = CreateScreenStateInDozeMap();
*state.mutable_map() = map;
@@ -533,6 +533,15 @@ std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampN
uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
}
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs);
+ event->write(uid);
+ event->write("eventType");
+ event->write("processName");
+ event->init();
+ return event;
+}
+
std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
auto logEvent = std::make_unique<LogEvent>(
@@ -544,6 +553,15 @@ std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
return logEvent;
}
+std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
+ int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) {
+ auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs);
+ event->write(uid);
+ event->write(state);
+ event->init();
+ return event;
+}
+
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key) {
sp<UidMap> uidMap = new UidMap();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index c02610540cf0..e1e134be6b81 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -192,6 +192,9 @@ std::unique_ptr<LogEvent> CreateSyncEndEvent(
std::unique_ptr<LogEvent> CreateAppCrashEvent(
const int uid, uint64_t timestampNs);
+// Create log event for an app crash.
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs);
+
// Create log event for acquiring wakelock.
std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
@@ -206,6 +209,10 @@ std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+// Create log event for uid process state change.
+std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
+ int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs);
+
// Helper function to create an AttributionNodeInternal proto.
AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index b5401755a3c8..8b62e2f83cff 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -76,9 +76,9 @@ public final class AccessibilityGestureEvent implements Parcelable {
GESTURE_SWIPE_RIGHT_AND_DOWN
})
@Retention(RetentionPolicy.SOURCE)
- public @interface GestureType {}
+ public @interface GestureId {}
- @GestureType
+ @GestureId
private final int mGestureId;
private final int mDisplayId;
@@ -110,7 +110,7 @@ public final class AccessibilityGestureEvent implements Parcelable {
* @return the performed gesture id.
*
*/
- @GestureType public int getGestureId() {
+ @GestureId public int getGestureId() {
return mGestureId;
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ebb03e765a47..764e5992fbd9 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -296,6 +296,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static void setDurationScale(float durationScale) {
sDurationScale = durationScale;
@@ -304,6 +305,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static float getDurationScale() {
return sDurationScale;
diff --git a/core/java/android/annotation/UserHandleAware.java b/core/java/android/annotation/UserHandleAware.java
new file mode 100644
index 000000000000..7d3d20b31b2a
--- /dev/null
+++ b/core/java/android/annotation/UserHandleAware.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates an API that uses {@code context.getUser} or {@code context.getUserId}
+ * to operate across users (as the user associated with the context)
+ * <p>
+ * To create a {@link android.content.Context} associated with a different user,
+ * use {@link android.content.Context#createContextAsUser} or
+ * {@link android.content.Context#createPackageContextAsUser}
+ * <p>
+ * Example:
+ * <pre>{@code
+ * {@literal @}UserHandleAware
+ * public abstract PackageInfo getPackageInfo({@literal @}NonNull String packageName,
+ * {@literal @}PackageInfoFlags int flags) throws NameNotFoundException;
+ * }</pre>
+ *
+ * @memberDoc This method uses {@linkplain android.content.Context#getUser}
+ * or {@linkplain android.content.Context#getUserId} to execute across users.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({TYPE, METHOD, CONSTRUCTOR, PACKAGE})
+public @interface UserHandleAware {
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6182def33206..f54e841fd2a0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2797,6 +2797,7 @@ public class Activity extends ContextThemeWrapper
* @see View#onMovedToDisplay(int, Configuration)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public void onMovedToDisplay(int displayId, Configuration config) {
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2e9b2afcc37a..6d63fd0936dd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -155,6 +155,12 @@ public class ActivityManager {
*/
public static final int INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL = 1 << 1;
+ /**
+ * Disable test API access for the newly started instrumentation.
+ * @hide
+ */
+ public static final int INSTR_FLAG_DISABLE_TEST_API_CHECKS = 1 << 2;
+
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
final Context mContext;
@@ -2976,6 +2982,7 @@ public class ActivityManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 92aabb591e03..de7cc9d53f2f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -219,7 +219,7 @@ public abstract class ActivityManagerInternal {
* @param userId
* @param event
* @param appToken ActivityRecord's appToken.
- * @param taskRoot TaskRecord's root
+ * @param taskRoot Task's root
*/
public abstract void updateActivityUsageStats(
ComponentName activity, @UserIdInt int userId, int event, IBinder appToken,
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 79ab67ac148c..91f8a3c7be85 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -412,8 +412,8 @@ public class ActivityView extends ViewGroup implements TaskEmbedder.Host {
return;
}
mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
- mTaskEmbedder.setListener(null);
mTaskEmbedder.release();
+ mTaskEmbedder.setListener(null);
mGuard.close();
mOpened = false;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 765c358748a3..afb787118107 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -581,6 +581,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public static final int OP_NONE = -1;
/** @hide Access to coarse location information. */
+ @UnsupportedAppUsage
@TestApi
public static final int OP_COARSE_LOCATION = 0;
/** @hide Access to fine location information. */
@@ -653,6 +654,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public static final int OP_WRITE_SETTINGS = 23;
/** @hide Required to draw on top of other apps. */
+ @UnsupportedAppUsage
@TestApi
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
/** @hide */
@@ -662,6 +664,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public static final int OP_CAMERA = 26;
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public static final int OP_RECORD_AUDIO = 27;
/** @hide */
@@ -809,6 +812,7 @@ public class AppOpsManager {
@UnsupportedAppUsage
public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
/** @hide Any app start foreground service. */
+ @UnsupportedAppUsage
@TestApi
public static final int OP_START_FOREGROUND = 76;
/** @hide */
@@ -2147,6 +2151,7 @@ public class AppOpsManager {
* Retrieve the permission associated with an operation, or null if there is not one.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static String opToPermission(int op) {
return sOpPerms[op];
@@ -2179,6 +2184,7 @@ public class AppOpsManager {
* to the corresponding app op.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static int permissionToOpCode(String permission) {
Integer boxedOpCode = sPermToOp.get(permission);
@@ -5281,6 +5287,7 @@ public class AppOpsManager {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
@@ -5627,6 +5634,7 @@ public class AppOpsManager {
/**
* {@hide}
*/
+ @UnsupportedAppUsage
@TestApi
public static int strOpToOp(@NonNull String op) {
Integer val = sOpStrToOp.get(op);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 75a1546c937f..1c8f4948eb85 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2361,6 +2361,7 @@ class ContextImpl extends Context {
return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
}
+ @UnsupportedAppUsage
@TestApi
@Override
public Display getDisplay() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2931f33e4cc4..fce74496d9c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3204,6 +3204,14 @@ public class Notification implements Parcelable
}
/**
+ * Sets the {@link BubbleMetadata} for this notification.
+ * @hide
+ */
+ public void setBubbleMetadata(BubbleMetadata data) {
+ mBubbleMetadata = data;
+ }
+
+ /**
* Returns whether the platform is allowed (by the app developer) to generate contextual actions
* for this notification.
*/
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index e6682d620b99..92bfee24d402 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -24,12 +24,22 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.IBinder;
+import android.os.IPullAtomCallback;
+import android.os.IPullAtomResultReceiver;
+import android.os.IStatsCompanionService;
import android.os.IStatsManager;
import android.os.IStatsPullerCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
import android.util.Slog;
+import android.util.StatsEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
/**
* API for statsd clients to send configurations and retrieve data.
@@ -43,8 +53,12 @@ public final class StatsManager {
private final Context mContext;
+ @GuardedBy("this")
private IStatsManager mService;
+ @GuardedBy("this")
+ private IStatsCompanionService mStatsCompanion;
+
/**
* Long extra of uid that added the relevant stats config.
*/
@@ -449,7 +463,9 @@ public final class StatsManager {
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*
* @hide
+ * @deprecated Please use registerPullAtomCallback
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
throws StatsUnavailableException {
@@ -472,6 +488,75 @@ public final class StatsManager {
}
}
+
+ /**
+ * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke pullData in the callback when the stats service determines that this atom needs to be
+ * pulled.
+ *
+ * @param atomTag The tag of the atom for this puller callback.
+ * @param coolDownNs The minimum time between successive pulls. A cache of the previous
+ * pull will be used if the time between pulls is less than coolDownNs.
+ * @param timeoutNs The maximum time a pull should take. Statsd will wait timeoutNs for
+ * the pull to complete before timing out and marking the pull as
+ * failed.
+ * @param additiveFields Fields that are added when mapping isolated uids to host uids.
+ * @param callback The callback to be invoked when the stats service pulls the atom.
+ * @throws RemoteException if unsuccessful due to failing to connect to system server.
+ *
+ * @hide
+ */
+ public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+ int[] additiveFields, @NonNull StatsPullAtomCallback callback,
+ @NonNull Executor executor) throws RemoteException, SecurityException {
+ synchronized (this) {
+ IStatsCompanionService service = getIStatsCompanionServiceLocked();
+ PullAtomCallbackInternal rec =
+ new PullAtomCallbackInternal(atomTag, callback, executor);
+ service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields, rec);
+ }
+ }
+
+ private static class PullAtomCallbackInternal extends IPullAtomCallback.Stub {
+ public final int mAtomId;
+ public final StatsPullAtomCallback mCallback;
+ public final Executor mExecutor;
+
+ PullAtomCallbackInternal(int atomId, StatsPullAtomCallback callback, Executor executor) {
+ mAtomId = atomId;
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver) {
+ mExecutor.execute(() -> {
+ List<StatsEvent> data = new ArrayList<>();
+ boolean success = mCallback.onPullAtom(atomTag, data);
+ StatsEvent[] arr = new StatsEvent[data.size()];
+ arr = data.toArray(arr);
+ try {
+ resultReceiver.pullFinished(atomTag, success, arr);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
+ }
+ });
+ }
+ }
+
+ /**
+ * Callback interface for pulling atoms requested by the stats service.
+ *
+ * @hide
+ */
+ public interface StatsPullAtomCallback {
+ /**
+ * Pull data for the specified atom tag, filling in the provided list of StatsEvent data.
+ * @return if the pull was successful
+ */
+ boolean onPullAtom(int atomTag, List<StatsEvent> data);
+ }
+
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
@@ -481,6 +566,7 @@ public final class StatsManager {
}
}
+ @GuardedBy("this")
private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
if (mService != null) {
return mService;
@@ -497,6 +583,16 @@ public final class StatsManager {
return mService;
}
+ @GuardedBy("this")
+ private IStatsCompanionService getIStatsCompanionServiceLocked() {
+ if (mStatsCompanion != null) {
+ return mStatsCompanion;
+ }
+ mStatsCompanion = IStatsCompanionService.Stub.asInterface(
+ ServiceManager.getService("statscompanion"));
+ return mStatsCompanion;
+ }
+
/**
* Exception thrown when communication with the stats service fails (eg if it is not available).
* This might be thrown early during boot before the stats service has started or if it crashed.
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index f4c6b50da714..8cb094f8a6a6 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -35,6 +35,8 @@ import android.util.proto.ProtoOutputStream;
import android.util.proto.WireTypeMismatchException;
import android.view.DisplayInfo;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.io.IOException;
/**
@@ -199,6 +201,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** @hide */
public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
+ @UnsupportedAppUsage
public WindowConfiguration() {
unset();
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ad671dfcf80a..9eff4b03b19e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3499,24 +3499,25 @@ public class DevicePolicyManager {
* Returns how complex the current user's screen lock is.
*
* <p>Note that when called from a profile which uses an unified challenge with its parent, the
- * screen lock complexity of the parent will be returned. However, this API does not support
- * explicitly querying the parent profile screen lock complexity via {@link
- * #getParentProfileInstance}.
+ * screen lock complexity of the parent will be returned.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
*
* @throws IllegalStateException if the user is not unlocked.
- * @throws SecurityException if the calling application does not have the permission
- * {@link permission#REQUEST_PASSWORD_COMPLEXITY}
+ * @throws SecurityException if the calling application does not have the permission
+ * {@link permission#REQUEST_PASSWORD_COMPLEXITY}
*/
@PasswordComplexity
@RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY)
public int getPasswordComplexity() {
- throwIfParentInstance("getPasswordComplexity");
if (mService == null) {
return PASSWORD_COMPLEXITY_NONE;
}
try {
- return mService.getPasswordComplexity();
+ return mService.getPasswordComplexity(mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9254,6 +9255,7 @@ public class DevicePolicyManager {
* <li>{@link #setPasswordExpirationTimeout}</li>
* <li>{@link #getPasswordExpiration}</li>
* <li>{@link #getPasswordMaximumLength}</li>
+ * <li>{@link #getPasswordComplexity}</li>
* <li>{@link #isActivePasswordSufficient}</li>
* <li>{@link #getCurrentFailedPasswordAttempts}</li>
* <li>{@link #getMaximumFailedPasswordsForWipe}</li>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6b505223163c..4894751b60a5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -84,7 +84,7 @@ interface IDevicePolicyManager {
boolean isActivePasswordSufficient(int userHandle, boolean parent);
boolean isProfileActivePasswordSufficientForParent(int userHandle);
- int getPasswordComplexity();
+ int getPasswordComplexity(boolean parent);
boolean isUsingUnifiedPassword(in ComponentName admin);
int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 8e40449fa546..6bade901826a 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -146,6 +146,7 @@ public class NetworkStatsManager {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public void setPollForce(boolean pollForce) {
if (pollForce) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 2657cc54b91a..61c8db5db124 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -65,6 +65,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Size;
+import android.util.SparseArray;
import com.android.internal.util.MimeIconUtils;
import com.android.internal.util.Preconditions;
@@ -2381,15 +2382,15 @@ public abstract class ContentResolver implements ContentInterface {
* true.
* @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
+ * @deprecated callers should consider migrating to
+ * {@link #notifyChange(Uri, ContentObserver, int)}, as it
+ * offers support for many more options than just
+ * {@link #NOTIFY_SYNC_TO_NETWORK}.
*/
+ @Deprecated
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
boolean syncToNetwork) {
- Preconditions.checkNotNull(uri, "uri");
- notifyChange(
- ContentProvider.getUriWithoutUserId(uri),
- observer,
- syncToNetwork,
- ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
+ notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0);
}
/**
@@ -2398,10 +2399,10 @@ public abstract class ContentResolver implements ContentInterface {
* To observe events sent through this call, use
* {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
* <p>
- * If syncToNetwork is true, this will attempt to schedule a local sync
- * using the sync adapter that's registered for the authority of the
- * provided uri. No account will be passed to the sync adapter, so all
- * matching accounts will be synchronized.
+ * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
+ * a local sync using the sync adapter that's registered for the authority
+ * of the provided uri. No account will be passed to the sync adapter, so
+ * all matching accounts will be synchronized.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#O}, all content
* notifications must be backed by a valid {@link ContentProvider}.
@@ -2427,21 +2428,71 @@ public abstract class ContentResolver implements ContentInterface {
}
/**
+ * Notify registered observers that several rows have been updated.
+ * <p>
+ * To observe events sent through this call, use
+ * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+ * <p>
+ * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
+ * a local sync using the sync adapter that's registered for the authority
+ * of the provided uri. No account will be passed to the sync adapter, so
+ * all matching accounts will be synchronized.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+ * notifications must be backed by a valid {@link ContentProvider}.
+ *
+ * @param uris The uris of the content that was changed.
+ * @param observer The observer that originated the change, may be
+ * <code>null</null>. The observer that originated the change
+ * will only receive the notification if it has requested to
+ * receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return
+ * true.
+ * @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
+ * {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
+ */
+ public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ @NotifyFlags int flags) {
+ Preconditions.checkNotNull(uris, "uris");
+
+ // Cluster based on user ID
+ final SparseArray<ArrayList<Uri>> clusteredByUser = new SparseArray<>();
+ for (Uri uri : uris) {
+ final int userId = ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+ ArrayList<Uri> list = clusteredByUser.get(userId);
+ if (list == null) {
+ list = new ArrayList<>();
+ clusteredByUser.put(userId, list);
+ }
+ list.add(ContentProvider.getUriWithoutUserId(uri));
+ }
+
+ for (int i = 0; i < clusteredByUser.size(); i++) {
+ final int userId = clusteredByUser.keyAt(i);
+ final ArrayList<Uri> list = clusteredByUser.valueAt(i);
+ notifyChange(list.toArray(new Uri[list.size()]), observer, flags, userId);
+ }
+ }
+
+ /**
* Notify registered observers within the designated user(s) that a row was updated.
*
+ * @deprecated callers should consider migrating to
+ * {@link #notifyChange(Uri, ContentObserver, int)}, as it
+ * offers support for many more options than just
+ * {@link #NOTIFY_SYNC_TO_NETWORK}.
* @hide
*/
+ @Deprecated
public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
@UserIdInt int userHandle) {
- try {
- getContentService().notifyChange(
- uri, observer == null ? null : observer.getContentObserver(),
- observer != null && observer.deliverSelfNotifications(),
- syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
- userHandle, mTargetSdkVersion, mContext.getPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle);
+ }
+
+ /** {@hide} */
+ public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
+ @UserIdInt int userHandle) {
+ notifyChange(new Uri[] { uri }, observer, flags, userHandle);
}
/**
@@ -2449,11 +2500,11 @@ public abstract class ContentResolver implements ContentInterface {
*
* @hide
*/
- public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
+ public void notifyChange(@NonNull Uri[] uris, ContentObserver observer, @NotifyFlags int flags,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
- uri, observer == null ? null : observer.getContentObserver(),
+ uris, observer == null ? null : observer.getContentObserver(),
observer != null && observer.deliverSelfNotifications(), flags,
userHandle, mTargetSdkVersion, mContext.getPackageName());
} catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 76722666d842..41b773e81c46 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5407,6 +5407,7 @@ public abstract class Context {
* Get the user associated with this context
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public @UserIdInt int getUserId() {
return android.os.UserHandle.myUserId();
@@ -5537,6 +5538,7 @@ public abstract class Context {
* @return Returns the {@link Display} object this context is associated with.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public abstract Display getDisplay();
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 79c366982dae..5bdea52d63e1 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -973,6 +973,7 @@ public class ContextWrapper extends Context {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
@Override
public Display getDisplay() {
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index a34a9951671c..03c99e1a2344 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -51,7 +51,7 @@ interface IContentService {
* hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL
* USER_CURRENT are properly interpreted.
*/
- void notifyChange(in Uri uri, IContentObserver observer,
+ void notifyChange(in Uri[] uris, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags,
int userHandle, int targetSdkVersion, String callingPackage);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4e7e7132b7df..ca374f938f1e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1940,6 +1940,7 @@ public class Intent implements Parcelable, Cloneable {
@RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@SystemApi
+ @TestApi
public static final String ACTION_MANAGE_DEFAULT_APP =
"android.intent.action.MANAGE_DEFAULT_APP";
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index 3f6451577258..0eea47a248af 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -20,6 +20,9 @@ import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.Calendar;
@@ -139,10 +142,10 @@ public class SyncStatusInfo implements Parcelable {
public final long[] perSourceLastSuccessTimes = new long[SOURCE_COUNT];
public final long[] perSourceLastFailureTimes = new long[SOURCE_COUNT];
- // Warning: It is up to the external caller to ensure there are
- // no race conditions when accessing this list
- @UnsupportedAppUsage
- private ArrayList<Long> periodicSyncTimes;
+ // Warning: It is up to the external caller to ensure there are
+ // no race conditions when accessing this list
+ @UnsupportedAppUsage
+ private ArrayList<Long> periodicSyncTimes;
private final ArrayList<Long> mLastEventTimes = new ArrayList<>();
private final ArrayList<String> mLastEvents = new ArrayList<>();
@@ -292,9 +295,28 @@ public class SyncStatusInfo implements Parcelable {
}
}
+ /**
+ * Copies all data from the given SyncStatusInfo object.
+ *
+ * @param other the SyncStatusInfo object to copy data from
+ */
public SyncStatusInfo(SyncStatusInfo other) {
authorityId = other.authorityId;
+ copyFrom(other);
+ }
+
+ /**
+ * Copies all data from the given SyncStatusInfo object except for its authority id.
+ *
+ * @param authorityId the new authority id
+ * @param other the SyncStatusInfo object to copy data from
+ */
+ public SyncStatusInfo(int authorityId, SyncStatusInfo other) {
+ this.authorityId = authorityId;
+ copyFrom(other);
+ }
+ private void copyFrom(SyncStatusInfo other) {
other.totalStats.copyTo(totalStats);
other.todayStats.copyTo(todayStats);
other.yesterdayStats.copyTo(yesterdayStats);
@@ -323,6 +345,14 @@ public class SyncStatusInfo implements Parcelable {
System.arraycopy(from, 0, to, 0, to.length);
}
+ public int getPeriodicSyncTimesSize() {
+ return periodicSyncTimes == null ? 0 : periodicSyncTimes.size();
+ }
+
+ public void addPeriodicSyncTime(long time) {
+ periodicSyncTimes = ArrayUtils.add(periodicSyncTimes, time);
+ }
+
@UnsupportedAppUsage
public void setPeriodicSyncTime(int index, long when) {
// The list is initialized lazily when scheduling occurs so we need to make sure
@@ -347,6 +377,24 @@ public class SyncStatusInfo implements Parcelable {
}
}
+ /**
+ * Populates {@code mLastEventTimes} and {@code mLastEvents} with the given list. <br>
+ * <i>Note: This method is mainly used to repopulate the event info from disk and it will clear
+ * both {@code mLastEventTimes} and {@code mLastEvents} before populating.</i>
+ *
+ * @param lastEventInformation the list to populate with
+ */
+ public void populateLastEventsInformation(ArrayList<Pair<Long, String>> lastEventInformation) {
+ mLastEventTimes.clear();
+ mLastEvents.clear();
+ final int size = lastEventInformation.size();
+ for (int i = 0; i < size; i++) {
+ final Pair<Long, String> lastEventInfo = lastEventInformation.get(i);
+ mLastEventTimes.add(lastEventInfo.first);
+ mLastEvents.add(lastEventInfo.second);
+ }
+ }
+
/** */
public void addEvent(String message) {
if (mLastEventTimes.size() >= MAX_EVENT_COUNT) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 1e4cc38030cb..e72444399dd0 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1237,6 +1237,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* Determines whether the {@link Activity} is considered translucent or floating.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static boolean isTranslucentOrFloating(TypedArray attributes) {
final boolean isTranslucent =
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d0a61eb38141..37c6f57e6379 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -470,6 +470,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*
* {@hide}
*/
+ @UnsupportedAppUsage
@TestApi
public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
@@ -733,6 +734,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public @ApplicationInfoPrivateFlags int privateFlags;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e0d6260c3ded..c56c3076c3be 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3332,6 +3332,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
@@ -3344,6 +3345,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
@@ -3977,6 +3979,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@NonNull
@TestApi
public abstract String getPermissionControllerPackageName();
@@ -4684,6 +4687,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
@@ -4694,6 +4698,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 053444b28f01..5a45d9f1bf46 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -613,6 +613,16 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public int navigationHidden;
+ /** @hide **/
+ @IntDef(prefix = {"ORIENTATION_"}, value = {
+ ORIENTATION_UNDEFINED,
+ ORIENTATION_PORTRAIT,
+ ORIENTATION_LANDSCAPE,
+ ORIENTATION_SQUARE
+ })
+ public @interface Orientation {
+ }
+
/** Constant for {@link #orientation}: a value indicating that no value has been set. */
public static final int ORIENTATION_UNDEFINED = 0;
/** Constant for {@link #orientation}, value corresponding to the
@@ -630,6 +640,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
*/
+ @Orientation
public int orientation;
/** Constant for {@link #uiMode}: bits that encode the mode type. */
@@ -798,6 +809,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public int assetsSeq;
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index a231a920a29b..3d0ac611b2df 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -23,6 +23,8 @@ import android.os.SystemProperties;
import android.util.Log;
import android.util.Printer;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.util.ArrayList;
/**
@@ -116,9 +118,15 @@ public final class SQLiteDebug {
* @see #nativeGetPagerStats(PagerStats)
*/
public static class PagerStats {
+
+ @UnsupportedAppUsage
+ public PagerStats() {
+ }
+
/** the current amount of memory checked out by sqlite using sqlite3_malloc().
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
+ @UnsupportedAppUsage
public int memoryUsed;
/** the number of bytes of page cache allocation which could not be sattisfied by the
@@ -128,16 +136,19 @@ public final class SQLiteDebug {
* that overflowed because no space was left in the page cache.
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
+ @UnsupportedAppUsage
public int pageCacheOverflow;
/** records the largest memory allocation request handed to sqlite3.
* documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
*/
+ @UnsupportedAppUsage
public int largestMemAlloc;
/** a list of {@link DbStats} - one for each main database opened by the applications
* running on the android device
*/
+ @UnsupportedAppUsage
public ArrayList<DbStats> dbStats;
}
@@ -146,16 +157,20 @@ public final class SQLiteDebug {
*/
public static class DbStats {
/** name of the database */
+ @UnsupportedAppUsage
public String dbName;
/** the page size for the database */
+ @UnsupportedAppUsage
public long pageSize;
/** the database size */
+ @UnsupportedAppUsage
public long dbSize;
/**
* Number of lookaside slots: http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
+ @UnsupportedAppUsage
public int lookaside;
/** statement cache stats: hits/misses/cachesize */
@@ -175,6 +190,7 @@ public final class SQLiteDebug {
* return all pager and database stats for the current process.
* @return {@link PagerStats}
*/
+ @UnsupportedAppUsage
public static PagerStats getDatabaseInfo() {
PagerStats stats = new PagerStats();
nativeGetPagerStats(stats);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index e3259ffa9d47..88877e254787 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -478,6 +478,7 @@ public final class NetworkCapabilities implements Parcelable {
* @return an array of capability values for this instance.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 95d66bb87064..39cb323d0662 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -304,7 +304,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
/**
- * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+ * Sets the
+ * <a class="external" href="https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-03.html">Next
* Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
*
* <p>For servers this is the sequence of protocols to advertise as
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index fda1539b59f5..a856975e2501 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -933,8 +933,7 @@ public class Binder implements IBinder {
int result = -1;
try {
- result = handleShellCommand(new ParcelFileDescriptor(in),
- new ParcelFileDescriptor(out), new ParcelFileDescriptor(err), args);
+ result = handleShellCommand(in, out, err, args);
} finally {
resultReceiver.send(result, null);
}
@@ -955,10 +954,9 @@ public class Binder implements IBinder {
* @hide
*/
// @SystemApi TODO Make it a system API.
- protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
- @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
- @NonNull String[] args) {
- FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor());
+ protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+ @NonNull FileDescriptor err, @NonNull String[] args) {
+ FileOutputStream ferr = new FileOutputStream(err);
PrintWriter pw = new FastPrintWriter(ferr);
pw.println("No shell command implementation.");
pw.flush();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 123ed6f611f5..733079691a15 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -109,6 +109,7 @@ public class Build {
* Whether this build was for an emulator device.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
@@ -239,6 +240,13 @@ public class Build {
public static final String RELEASE = getString("ro.build.version.release");
/**
+ * The version string we show to the user; may be {@link #RELEASE} or
+ * {@link #CODENAME} if not a final release build.
+ */
+ @NonNull public static final String RELEASE_OR_CODENAME = getString(
+ "ro.build.version.release_or_codename");
+
+ /**
* The base OS build the product is based on.
*/
public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", "");
@@ -337,8 +345,8 @@ public class Build {
/**
* @hide
*/
- @TestApi
@UnsupportedAppUsage
+ @TestApi
public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0])
? new String[0] : ALL_CODENAMES;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 947b0a1efebd..034e6a7a06c4 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -177,13 +177,6 @@ public class GraphicsEnvironment {
}
/**
- * Check whether application is debuggable
- */
- private static boolean isDebuggable(Context context) {
- return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
- }
-
- /**
* Check whether application is has set the manifest metadata for layer injection.
*/
private static boolean canInjectLayers(ApplicationInfo ai) {
@@ -246,7 +239,7 @@ public class GraphicsEnvironment {
// 2. ENABLE_GPU_DEBUG_LAYERS is true
// 3. Package name is equal to GPU_DEBUG_APP
- if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1) || canInjectLayers(ai)) {
+ if (isDebuggable() || canInjectLayers(ai)) {
final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
@@ -441,9 +434,7 @@ public class GraphicsEnvironment {
* Check for ANGLE debug package, but only for apps that can load them (dumpable)
*/
private String getAngleDebugPackage(Context context, Bundle coreSettings) {
- final boolean appIsDebuggable = isDebuggable(context);
- final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
- if (appIsDebuggable || deviceIsDebuggable) {
+ if (isDebuggable()) {
String debugPackage;
if (coreSettings != null) {
@@ -478,12 +469,8 @@ public class GraphicsEnvironment {
* - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
* debugging (PR_SET_DUMPABLE).
*/
- final boolean appIsDebuggable = isDebuggable(context);
- final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
- if (!(appIsDebuggable || deviceIsDebuggable)) {
- Log.v(TAG, "Skipping loading temporary rules file: "
- + "appIsDebuggable = " + appIsDebuggable + ", "
- + "adbRootEnabled = " + deviceIsDebuggable);
+ if (!isDebuggable()) {
+ Log.v(TAG, "Skipping loading temporary rules file");
return false;
}
@@ -742,7 +729,7 @@ public class GraphicsEnvironment {
final boolean enablePrereleaseDriver =
(ai.metaData != null && ai.metaData.getBoolean(METADATA_DEVELOPER_DRIVER_ENABLE))
- || getCanLoadSystemLibraries() == 1;
+ || isDebuggable();
// Priority for Game Driver settings global on confliction (Higher priority comes first):
// 1. GAME_DRIVER_ALL_APPS
@@ -918,7 +905,7 @@ public class GraphicsEnvironment {
return "";
}
- private static native int getCanLoadSystemLibraries();
+ private static native boolean isDebuggable();
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDebugLayersGLES(String layers);
diff --git a/core/java/android/os/IPullAtomCallback.aidl b/core/java/android/os/IPullAtomCallback.aidl
new file mode 100644
index 000000000000..88d3c3e46ff5
--- /dev/null
+++ b/core/java/android/os/IPullAtomCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.IPullAtomResultReceiver;
+
+/**
+ * Binder interface to pull atoms for the stats service.
+ * {@hide}
+ */
+interface IPullAtomCallback {
+ /**
+ * Initiate a request for a pull for an atom.
+ */
+ void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver);
+
+}
diff --git a/core/java/android/os/IPullAtomResultReceiver.aidl b/core/java/android/os/IPullAtomResultReceiver.aidl
new file mode 100644
index 000000000000..bfb35ff0c9d1
--- /dev/null
+++ b/core/java/android/os/IPullAtomResultReceiver.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.util.StatsEvent;
+
+/**
+ * Binder interface to pull atoms for the stats service.
+ * {@hide}
+ */
+interface IPullAtomResultReceiver {
+
+ /**
+ * Indicate that a pull request for an atom is complete.
+ */
+ oneway void pullFinished(int atomTag, boolean success, in StatsEvent[] output);
+
+}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 0751b964f85e..22a25374e064 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -16,6 +16,7 @@
package android.os;
+import android.os.IPullAtomCallback;
import android.os.StatsDimensionsValue;
import android.os.StatsLogEventWrapper;
@@ -85,4 +86,8 @@ interface IStatsCompanionService {
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
oneway void triggerUidSnapshot();
+
+ /** Tells StatsCompanionService to tell statsd to register a puller for the given atom id */
+ oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+ in int[] additiveFields, IPullAtomCallback pullerCallback);
}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index e3f9326048d1..29871b6cf017 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -17,6 +17,7 @@
package android.os;
import android.os.IStatsPullerCallback;
+import android.os.IPullAtomCallback;
import android.os.ParcelFileDescriptor;
/**
@@ -188,11 +189,19 @@ interface IStatsManager {
* for the specified vendor atom tag.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+ * @deprecated please use registerPullAtomCallback.
*/
oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
String packageName);
/**
+ * Registers a puller callback function that, when invoked, pulls the data
+ * for the specified atom tag.
+ */
+ oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownNs, long timeoutNs,
+ in int[] additiveFields, IPullAtomCallback pullerCallback);
+
+ /**
* Unregisters a puller callback function for the given vendor atom.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl
index 1684aeb0d666..c3e1e55dde06 100644
--- a/core/java/android/os/IStatsPullerCallback.aidl
+++ b/core/java/android/os/IStatsPullerCallback.aidl
@@ -19,6 +19,7 @@ package android.os;
import android.os.StatsLogEventWrapper;
/**
+ * DEPRECATED
* Binder interface to pull atoms for the stats service.
* {@hide}
*/
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c5f169802230..f98fdc393de3 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -468,6 +468,7 @@ public final class MessageQueue {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
@@ -512,6 +513,7 @@ public final class MessageQueue {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 43b9c6728868..6408f6170fce 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -229,6 +229,7 @@ public class Process {
* First uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int FIRST_ISOLATED_UID = 99000;
@@ -236,6 +237,7 @@ public class Process {
* Last uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int LAST_ISOLATED_UID = 99999;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index c707ba839336..0bf634e799cd 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1892,6 +1892,7 @@ public final class StrictMode {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public static void conditionallyCheckInstanceCounts() {
VmPolicy policy = getVmPolicy();
@@ -2751,6 +2752,7 @@ public final class StrictMode {
}
/** Create an instance of ViolationInfo initialized from a Parcel. */
+ @UnsupportedAppUsage
public ViolationInfo(Parcel in) {
this(in, false);
}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 3558fcd24993..537cb9889805 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -198,6 +198,7 @@ public final class UserHandle implements Parcelable {
* "it's system", because of isolated UIDs. Use {@link #isCore} for that.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static boolean isApp(int uid) {
if (uid > 0) {
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 26da0a0aee07..5769c34c6d20 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -27,6 +27,8 @@ import android.hardware.vibrator.V1_3.Effect;
import android.net.Uri;
import android.util.MathUtils;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
@@ -77,6 +79,7 @@ public abstract class VibrationEffect implements Parcelable {
* @see #get(int)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int EFFECT_THUD = Effect.THUD;
@@ -85,6 +88,7 @@ public abstract class VibrationEffect implements Parcelable {
* @see #get(int)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int EFFECT_POP = Effect.POP;
@@ -126,6 +130,7 @@ public abstract class VibrationEffect implements Parcelable {
* @see #get(Uri, Context)
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int[] RINGTONES = {
Effect.RINGTONE_1,
@@ -493,6 +498,7 @@ public abstract class VibrationEffect implements Parcelable {
out.writeInt(mAmplitude);
}
+ @UnsupportedAppUsage
public static final @android.annotation.NonNull Parcelable.Creator<OneShot> CREATOR =
new Parcelable.Creator<OneShot>() {
@Override
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 9cc9aac490c7..825fc64df5cc 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -92,6 +92,7 @@ public class WorkSource implements Parcelable {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public WorkSource(int uid) {
mNum = 1;
@@ -138,12 +139,14 @@ public class WorkSource implements Parcelable {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public int size() {
return mNum;
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public int get(int index) {
return mUids[index];
@@ -165,6 +168,7 @@ public class WorkSource implements Parcelable {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public String getName(int index) {
return mNames != null ? mNames[index] : null;
@@ -419,6 +423,7 @@ public class WorkSource implements Parcelable {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public boolean add(int uid) {
if (mNum <= 0) {
@@ -439,6 +444,7 @@ public class WorkSource implements Parcelable {
}
/** @hide */
+ @UnsupportedAppUsage
@TestApi
public boolean add(int uid, String name) {
if (mNum <= 0) {
diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java
index de983595efd4..384342c894d5 100644
--- a/core/java/android/os/health/HealthStatsParceler.java
+++ b/core/java/android/os/health/HealthStatsParceler.java
@@ -19,10 +19,8 @@ package android.os.health;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArrayMap;
-import java.util.Arrays;
-import java.util.Map;
+import dalvik.annotation.compat.UnsupportedAppUsage;
/**
* Class to allow sending the HealthStats through aidl generated glue.
@@ -41,6 +39,7 @@ public class HealthStatsParceler implements Parcelable {
private HealthStatsWriter mWriter;
private HealthStats mHealthStats;
+ @UnsupportedAppUsage
public static final @android.annotation.NonNull Parcelable.Creator<HealthStatsParceler> CREATOR
= new Parcelable.Creator<HealthStatsParceler>() {
public HealthStatsParceler createFromParcel(Parcel in) {
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
new file mode 100644
index 000000000000..1c832ca9e6db
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+
+/** @hide */
+interface IIncrementalService {
+ /**
+ * A set of flags for the |createMode| parameters when creating a new Incremental storage.
+ */
+ const int CREATE_MODE_TEMPORARY_BIND = 1;
+ const int CREATE_MODE_PERMANENT_BIND = 2;
+ const int CREATE_MODE_CREATE = 4;
+ const int CREATE_MODE_OPEN_EXISTING = 8;
+
+ /**
+ * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
+ */
+ int openStorage(in @utf8InCpp String path);
+ int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
+ int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
+
+ /**
+ * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
+ */
+ const int BIND_TEMPORARY = 0;
+ const int BIND_PERMANENT = 1;
+ int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
+
+ /**
+ * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
+ */
+ int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
+
+ /**
+ * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
+ */
+ int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Creates a file under a storage, specifying its name, size and metadata.
+ */
+ int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
+
+ /**
+ * Creates a file under a storage. Content of the file is from a range inside another file.
+ * Both files are specified by relative paths under storage.
+ */
+ int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
+
+ /**
+ * Creates a hard link between two files in a storage.
+ * Both source and destination are specified by relative paths under storage.
+ */
+ int makeLink(int storageId, in @utf8InCpp String sourcePathUnderStorage, in @utf8InCpp String destPathUnderStorage);
+
+ /**
+ * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
+ */
+ int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
+ */
+ boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
+
+ /**
+ * Reads the metadata of a file. File is specified by relative path under storage.
+ */
+ byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
+ * Returns the list of file paths under a storage.
+ */
+ @utf8InCpp String[] getFileList(int storageId);
+
+ /**
+ * Starts loading data for a storage.
+ */
+ boolean startLoading(int storageId);
+}
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
new file mode 100644
index 000000000000..12740eaf3425
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.service.incremental.IIncrementalDataLoaderStatusListener;
+
+/**
+ * Binder service to receive calls from native Incremental Service and handle Java tasks such as
+ * looking up data loader service package names, binding and talking to the data loader service.
+ * @hide
+ */
+interface IIncrementalServiceProxy {
+ boolean prepareDataLoader(int mountId,
+ in IncrementalFileSystemControlParcel control,
+ in IncrementalDataLoaderParamsParcel params,
+ in IIncrementalDataLoaderStatusListener listener);
+ boolean startDataLoader(int mountId);
+ void showHealthBlockedUI(int mountId);
+ void destroyDataLoader(int mountId);
+ void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
+}
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
new file mode 100644
index 000000000000..50c28f0a4c17
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.os.incremental.NamedParcelFileDescriptor;
+
+/**
+ * Class for holding data loader configuration parameters.
+ * @hide
+ */
+parcelable IncrementalDataLoaderParamsParcel {
+ @utf8InCpp String staticUri;
+ @utf8InCpp String packageName;
+ NamedParcelFileDescriptor[] dynamicArgs;
+}
diff --git a/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
new file mode 100644
index 000000000000..0ae353d2741f
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+/**
+ * Wraps two file descriptors that Incremental Service uses to communicate
+ * with Incremental FileSystem.
+ * @hide
+ */
+parcelable IncrementalFileSystemControlParcel {
+ @nullable ParcelFileDescriptor cmd;
+ @nullable ParcelFileDescriptor log;
+}
diff --git a/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
new file mode 100644
index 000000000000..038ced1744a1
--- /dev/null
+++ b/core/java/android/os/incremental/NamedParcelFileDescriptor.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * A named ParcelFileDescriptor.
+ * @hide
+ */
+parcelable NamedParcelFileDescriptor {
+ @utf8InCpp String name;
+ ParcelFileDescriptor fd;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2d8af83c7ca7..ac7a0a8d8b5c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -779,7 +779,12 @@ public class StorageManager {
/** {@hide} */
public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
if (emulatedVol != null) {
- return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
+ String id = emulatedVol.getId();
+ int idx = id.indexOf(";");
+ if (idx != -1) {
+ id = id.substring(0, idx);
+ }
+ return findVolumeById(id.replace("emulated", "private"));
} else {
return null;
}
@@ -789,7 +794,8 @@ public class StorageManager {
@UnsupportedAppUsage
public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
if (privateVol != null) {
- return findVolumeById(privateVol.getId().replace("private", "emulated"));
+ return findVolumeById(privateVol.getId().replace("private", "emulated") + ";"
+ + mContext.getUserId());
} else {
return null;
}
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 6280600823d7..aefe8430f9de 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -173,6 +173,7 @@ public final class StorageVolume implements Parcelable {
* @return the mount path
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public String getPath() {
return mPath.toString();
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 7699a0529826..d6ec52fac8a5 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -266,7 +266,7 @@ public class VolumeInfo implements Parcelable {
@UnsupportedAppUsage
public @Nullable String getDescription() {
- if (ID_PRIVATE_INTERNAL.equals(id) || ID_EMULATED_INTERNAL.equals(id)) {
+ if (ID_PRIVATE_INTERNAL.equals(id) || id.startsWith(ID_EMULATED_INTERNAL + ";")) {
return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
} else if (!TextUtils.isEmpty(fsLabel)) {
return fsLabel;
@@ -301,13 +301,20 @@ public class VolumeInfo implements Parcelable {
}
public boolean isVisibleForUser(int userId) {
- if ((type == TYPE_PUBLIC || type == TYPE_STUB) && mountUserId == userId) {
- return isVisible();
- } else if (type == TYPE_EMULATED) {
+ if ((type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED)
+ && mountUserId == userId) {
return isVisible();
- } else {
- return false;
}
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if this volume is the primary emulated volume for {@code userId},
+ * {@code false} otherwise.
+ */
+ @UnsupportedAppUsage
+ public boolean isPrimaryEmulatedForUser(int userId) {
+ return id.equals(ID_EMULATED_INTERNAL + ";" + userId);
}
public boolean isVisibleForRead(int userId) {
@@ -390,7 +397,7 @@ public class VolumeInfo implements Parcelable {
derivedFsUuid = privateVol.fsUuid;
}
- if (ID_EMULATED_INTERNAL.equals(id)) {
+ if (isPrimaryEmulatedForUser(userId)) {
removable = false;
} else {
removable = true;
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d862d6022154..7285166cdd5f 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -1862,6 +1862,7 @@ public final class CalendarContract {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
_SYNC_ID,
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index af3a16c987e6..f10e184ccf5a 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -126,6 +126,7 @@ public final class ContactsContract {
* Prefix for column names that are not visible to client apps.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String HIDDEN_COLUMN_PREFIX = "x_";
@@ -6069,6 +6070,7 @@ public final class ContactsContract {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final Uri ENTERPRISE_CONTENT_URI =
Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index aa67d9779da4..01f9c7300fa1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -104,7 +104,14 @@ public final class MediaStore {
/** The authority for the media provider */
public static final String AUTHORITY = "media";
/** A content:// style uri to the authority for the media provider */
- public static final @NonNull Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+ public static final @NonNull Uri AUTHORITY_URI =
+ Uri.parse("content://" + AUTHORITY);
+
+ /** @hide */
+ public static final String AUTHORITY_LEGACY = "media_legacy";
+ /** @hide */
+ public static final @NonNull Uri AUTHORITY_LEGACY_URI =
+ Uri.parse("content://" + AUTHORITY_LEGACY);
/**
* Synthetic volume name that provides a view of all content across the
@@ -878,6 +885,16 @@ public final class MediaStore {
}
/**
+ * Rewrite the given {@link Uri} to point at
+ * {@link MediaStore#AUTHORITY_LEGACY}.
+ *
+ * @hide
+ */
+ public static @NonNull Uri rewriteToLegacy(@NonNull Uri uri) {
+ return uri.buildUpon().authority(MediaStore.AUTHORITY_LEGACY).build();
+ }
+
+ /**
* Common media metadata columns.
*/
public interface MediaColumns extends BaseColumns {
@@ -3477,11 +3494,15 @@ public final class MediaStore {
*/
public static @NonNull String getVolumeName(@NonNull Uri uri) {
final List<String> segments = uri.getPathSegments();
- if (uri.getAuthority().equals(AUTHORITY) && segments != null && segments.size() > 0) {
- return segments.get(0);
- } else {
- throw new IllegalArgumentException("Missing volume name: " + uri);
+ switch (uri.getAuthority()) {
+ case AUTHORITY:
+ case AUTHORITY_LEGACY: {
+ if (segments != null && segments.size() > 0) {
+ return segments.get(0);
+ }
+ }
}
+ throw new IllegalArgumentException("Missing volume name: " + uri);
}
/** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 381d4921932f..ac53f1b27680 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -836,9 +836,9 @@ public final class Settings {
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
* <p>
- * Input: Optionally, the Intent's data URI can specify the application package name to
- * directly invoke the management GUI specific to the package name. For example
- * "package:com.my.app".
+ * Input: Optionally, in versions of Android prior to 11, the Intent's data URI can specify the
+ * application package name to directly invoke the management GUI specific to the package name.
+ * For example "package:com.my.app".
* <p>
* Output: Nothing.
*/
@@ -1262,6 +1262,33 @@ public final class Settings {
= "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
/**
+ * Activity Action: Show notification listener permission settings page for app.
+ * <p>
+ * Users can grant and deny access to notifications for a {@link ComponentName} from here.
+ * See
+ * {@link android.app.NotificationManager#isNotificationListenerAccessGranted(ComponentName)}
+ * for more details.
+ * <p>
+ * Input: The extra {@link #EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME} containing the name
+ * of the component to grant or revoke notification listener access to.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS =
+ "android.settings.NOTIFICATION_LISTENER_DETAIL_SETTINGS";
+
+ /**
+ * Activity Extra: What component name to show the notification listener permission
+ * page for.
+ * <p>
+ * A string extra containing a {@link ComponentName}. This must be passed as an extra field to
+ * {@link #ACTION_NOTIFICATION_LISTENER_DETAIL_SETTINGS}.
+ */
+ public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME =
+ "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
+
+ /**
* Activity Action: Show Do Not Disturb access settings.
* <p>
* Users can grant and deny access to Do Not Disturb configuration from here. Managed
@@ -2060,6 +2087,7 @@ public final class Settings {
* This is the only type of reset available to non-system clients.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final int RESET_MODE_PACKAGE_DEFAULTS = 1;
@@ -6137,6 +6165,7 @@ public final class Settings {
* shortcut. Must be its flattened {@link ComponentName}.
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
"accessibility_shortcut_target_service";
@@ -6294,6 +6323,7 @@ public final class Settings {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
"accessibility_display_magnification_enabled";
@@ -7930,6 +7960,7 @@ public final class Settings {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
@@ -8077,6 +8108,7 @@ public final class Settings {
* The value is boolean (1 or 0).
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static final String NOTIFICATION_BADGING = "notification_badging";
@@ -8343,7 +8375,6 @@ public final class Settings {
INSTANT_APP_SETTINGS.add(ANDROID_ID);
- INSTANT_APP_SETTINGS.add(PACKAGE_VERIFIER_USER_CONSENT);
INSTANT_APP_SETTINGS.add(ALLOW_MOCK_LOCATION);
}
@@ -10053,25 +10084,26 @@ public final class Settings {
*/
public static final String MODE_RINGER = "mode_ringer";
- /**
- * Overlay display devices setting.
- * The associated value is a specially formatted string that describes the
- * size and density of simulated secondary display devices.
- * <p>
- * Format: {width}x{height}/{dpi};...
- * </p><p>
- * Example:
- * <ul>
- * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
- * <li><code>1920x1080/320;1280x720/213</code>: make two overlays, the first
- * at 1080p and the second at 720p.</li>
- * <li>If the value is empty, then no overlay display devices are created.</li>
- * </ul></p>
- *
- * @hide
- */
- @TestApi
- public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
+ /**
+ * Overlay display devices setting.
+ * The associated value is a specially formatted string that describes the
+ * size and density of simulated secondary display devices.
+ * <p>
+ * Format: {width}x{height}/{dpi};...
+ * </p><p>
+ * Example:
+ * <ul>
+ * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
+ * <li><code>1920x1080/320;1280x720/213</code>: make two overlays, the first
+ * at 1080p and the second at 720p.</li>
+ * <li>If the value is empty, then no overlay display devices are created.</li>
+ * </ul></p>
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ @TestApi
+ public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
/**
* Threshold values for the duration and level of a discharge cycle,
@@ -10720,6 +10752,7 @@ public final class Settings {
* @hide
* @see com.android.server.power.batterysaver.BatterySaverPolicy
*/
+ @UnsupportedAppUsage
@TestApi
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 12c25806d666..bc6a9e848e2a 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -21,6 +21,7 @@ import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
@@ -104,6 +105,26 @@ public abstract class EuiccService extends Service {
"android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
/**
+ * Intent action sent by the LPA to launch a carrier app Activity for eSIM activation, e.g. a
+ * carrier login screen. Carrier apps wishing to support this activation method must implement
+ * an Activity that responds to this intent action. Upon completion, the Activity must return
+ * one of the following results to the LPA:
+ *
+ * <p>{@code Activity.RESULT_CANCELED}: The LPA should treat this as an back button and abort
+ * the activation flow.
+ * <p>{@code Activity.RESULT_OK}: The LPA should try to get an activation code from the carrier
+ * app by binding to the carrier app service implementing
+ * {@link #ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
+ * <p>{@code Activity.RESULT_OK} with
+ * {@link android.telephony.euicc.EuiccManager#EXTRA_USE_QR_SCANNER} set to true: The LPA should
+ * start a QR scanner for the user to scan an eSIM profile QR code.
+ * <p>For other results: The LPA should treat this as an error.
+ **/
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_START_CARRIER_ACTIVATION =
+ "android.service.euicc.action.START_CARRIER_ACTIVATION";
+
+ /**
* @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS
* The difference is this one is used by system to bring up the LUI.
*/
@@ -138,6 +159,15 @@ public abstract class EuiccService extends Service {
public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
"android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
+ /**
+ * @see android.telephony.euicc.EuiccManager#ACTION_START_EUICC_ACTIVATION. This is
+ * a protected intent that can only be sent by the system, and requires the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_START_EUICC_ACTIVATION =
+ "android.service.euicc.action.START_EUICC_ACTIVATION";
+
// LUI resolution actions. These are called by the platform to resolve errors in situations that
// require user interaction.
// TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
@@ -516,7 +546,7 @@ public abstract class EuiccService extends Service {
* @see android.telephony.euicc.EuiccManager#eraseSubscriptions
*
* @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
- * and use {@link #onEraseSubscriptionsWithOptions(int, int)} instead
+ * and use {@link #onEraseSubscriptions(int, int)} instead
*/
@Deprecated
public abstract int onEraseSubscriptions(int slotId);
@@ -533,7 +563,7 @@ public abstract class EuiccService extends Service {
* constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
* @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions
*/
- public int onEraseSubscriptionsWithOptions(int slotIndex, @ResetOption int options) {
+ public int onEraseSubscriptions(int slotIndex, @ResetOption int options) {
throw new UnsupportedOperationException(
"This method must be overridden to enable the ResetOption parameter");
}
@@ -779,8 +809,7 @@ public abstract class EuiccService extends Service {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- int result = EuiccService.this.onEraseSubscriptionsWithOptions(
- slotIndex, options);
+ int result = EuiccService.this.onEraseSubscriptions(slotIndex, options);
try {
callback.onComplete(result);
} catch (RemoteException e) {
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
new file mode 100644
index 000000000000..723fc594bd72
--- /dev/null
+++ b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+import android.os.incremental.IncrementalFileSystemControlParcel;
+import android.service.incremental.IIncrementalDataLoaderStatusListener;
+
+/** @hide */
+oneway interface IIncrementalDataLoaderService {
+ void createDataLoader(in int storageId,
+ in IncrementalFileSystemControlParcel control,
+ in IncrementalDataLoaderParamsParcel params,
+ in IIncrementalDataLoaderStatusListener listener,
+ in boolean start);
+ void startDataLoader(in int storageId);
+ void stopDataLoader(in int storageId);
+ void destroyDataLoader(in int storageId);
+ void onFileCreated(in int storageId, in long inode, in byte[] metadata);
+}
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
new file mode 100644
index 000000000000..f04242dc6c02
--- /dev/null
+++ b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.incremental;
+
+/**
+ * Callbacks from DataLoaderService to IncrementalService to report data loader status.
+ * @hide
+ */
+oneway interface IIncrementalDataLoaderStatusListener {
+ /** Data loader status */
+ const int DATA_LOADER_READY = 0;
+ const int DATA_LOADER_NOT_READY = 1;
+ const int DATA_LOADER_RUNNING = 2;
+ const int DATA_LOADER_STOPPED = 3;
+ const int DATA_LOADER_SLOW_CONNECTION = 4;
+ const int DATA_LOADER_NO_CONNECTION = 5;
+ const int DATA_LOADER_CONNECTION_OK = 6;
+
+ /** Data loader status callback */
+ void onStatusChanged(in int storageId, in int status);
+}
+
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e784ad3e3188..d5c67668b88e 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -176,14 +176,10 @@ public abstract class WallpaperService extends Service {
int mCurWindowPrivateFlags = mWindowPrivateFlags;
final Rect mVisibleInsets = new Rect();
final Rect mWinFrame = new Rect();
- final Rect mOverscanInsets = new Rect();
final Rect mContentInsets = new Rect();
final Rect mStableInsets = new Rect();
- final Rect mOutsets = new Rect();
- final Rect mDispatchedOverscanInsets = new Rect();
final Rect mDispatchedContentInsets = new Rect();
final Rect mDispatchedStableInsets = new Rect();
- final Rect mDispatchedOutsets = new Rect();
final Rect mFinalSystemInsets = new Rect();
final Rect mFinalStableInsets = new Rect();
final Rect mBackdropFrame = new Rect();
@@ -317,13 +313,13 @@ public abstract class WallpaperService extends Service {
final BaseIWindow mWindow = new BaseIWindow() {
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ public void resized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
- Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
- reportDraw ? 1 : 0, outsets);
+ Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+ reportDraw ? 1 : 0);
mCaller.sendMessage(msg);
}
@@ -822,7 +818,7 @@ public abstract class WallpaperService extends Service {
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
- mOutsets, mDisplayCutout, inputChannel,
+ mDisplayCutout, inputChannel,
mInsetsState) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
@@ -838,17 +834,13 @@ public abstract class WallpaperService extends Service {
if (!fixedSize) {
mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding);
- mLayout.surfaceInsets.left += mOutsets.left;
- mLayout.surfaceInsets.top += mOutsets.top;
- mLayout.surfaceInsets.right += mOutsets.right;
- mLayout.surfaceInsets.bottom += mOutsets.bottom;
} else {
mLayout.surfaceInsets.set(0, 0, 0, 0);
}
final int relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
- View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
+ View.VISIBLE, 0, -1, mWinFrame, mContentInsets,
+ mVisibleInsets, mStableInsets, mBackdropFrame,
mDisplayCutout, mMergedConfiguration, mSurfaceControl,
mInsetsState);
if (mSurfaceControl.isValid()) {
@@ -864,12 +856,8 @@ public abstract class WallpaperService extends Service {
if (!fixedSize) {
final Rect padding = mIWallpaperEngine.mDisplayPadding;
- w += padding.left + padding.right + mOutsets.left + mOutsets.right;
- h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom;
- mOverscanInsets.left += padding.left;
- mOverscanInsets.top += padding.top;
- mOverscanInsets.right += padding.right;
- mOverscanInsets.bottom += padding.bottom;
+ w += padding.left + padding.right;
+ h += padding.top + padding.bottom;
mContentInsets.left += padding.left;
mContentInsets.top += padding.top;
mContentInsets.right += padding.right;
@@ -898,10 +886,8 @@ public abstract class WallpaperService extends Service {
Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight);
}
- insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets);
insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
- insetsChanged |= !mDispatchedOutsets.equals(mOutsets);
insetsChanged |= !mDispatchedDisplayCutout.equals(mDisplayCutout.get());
mSurfaceHolder.setSurfaceFrameSize(w, h);
@@ -961,16 +947,9 @@ public abstract class WallpaperService extends Service {
}
if (insetsChanged) {
- mDispatchedOverscanInsets.set(mOverscanInsets);
- mDispatchedOverscanInsets.left += mOutsets.left;
- mDispatchedOverscanInsets.top += mOutsets.top;
- mDispatchedOverscanInsets.right += mOutsets.right;
- mDispatchedOverscanInsets.bottom += mOutsets.bottom;
mDispatchedContentInsets.set(mContentInsets);
mDispatchedStableInsets.set(mStableInsets);
- mDispatchedOutsets.set(mOutsets);
mDispatchedDisplayCutout = mDisplayCutout.get();
- mFinalSystemInsets.set(mDispatchedOverscanInsets);
mFinalStableInsets.set(mDispatchedStableInsets);
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
mFinalStableInsets,
@@ -1457,7 +1436,6 @@ public abstract class WallpaperService extends Service {
} break;
case MSG_WINDOW_RESIZED: {
final boolean reportDraw = message.arg1 != 0;
- mEngine.mOutsets.set((Rect) message.obj);
mEngine.updateSurface(true, false, reportDraw);
mEngine.doOffsetsChanged(true);
} break;
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 7c7223c04b59..451a669d98fd 100755
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -23,9 +23,8 @@ import android.os.SystemProperties;
/**
* A structure describing general information about a display, such as its
* size, density, and font scaling.
- * <p>To access the DisplayMetrics members, initialize an object like this:</p>
- * <pre> DisplayMetrics metrics = new DisplayMetrics();
- * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
+ * <p>To access the DisplayMetrics members, retrieve display metrics like this:</p>
+ * <pre>context.getResources().getDisplayMetrics();</pre>
*/
public class DisplayMetrics {
/**
@@ -245,7 +244,7 @@ public class DisplayMetrics {
* this density value will be 1; on a 120 dpi screen it would be .75; etc.
*
* <p>This value does not exactly follow the real screen size (as given by
- * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
+ * {@link #xdpi} and {@link #ydpi}), but rather is used to scale the size of
* the overall UI in steps based on gross changes in the display dpi. For
* example, a 240x320 screen will have a density of 1 even if its width is
* 1.8", 1.3", etc. However, if the screen resolution is increased to
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index af1a51f68d71..12a55c74bd3e 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -56,6 +56,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
DEFAULT_FLAGS.put("settings_work_profile", "false");
+ DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
}
/**
diff --git a/core/java/android/util/StatsEvent.aidl b/core/java/android/util/StatsEvent.aidl
new file mode 100644
index 000000000000..deac873b0a04
--- /dev/null
+++ b/core/java/android/util/StatsEvent.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+parcelable StatsEvent cpp_header "android/util/StatsEvent.h";
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index a21f9e09ced5..10c9d87dfbe8 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -20,6 +20,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
@@ -42,7 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;
* </pre>
* @hide
**/
-public final class StatsEvent {
+public final class StatsEvent implements Parcelable {
private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;
// Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
@@ -63,7 +65,7 @@ public final class StatsEvent {
* Returns a new StatsEvent.Builder for building StatsEvent object.
**/
@NonNull
- public StatsEvent.Builder newBuilder() {
+ public static StatsEvent.Builder newBuilder() {
return new StatsEvent.Builder(Buffer.obtain());
}
@@ -631,4 +633,39 @@ public final class StatsEvent {
return 0;
}
}
+
+ /**
+ * Boilerplate for Parcel.
+ *
+ * @hide
+ */
+ public static final @NonNull Parcelable.Creator<StatsEvent> CREATOR =
+ new Parcelable.Creator<StatsEvent>() {
+ public StatsEvent createFromParcel(Parcel in) {
+ // Purposefully leaving this method not implemented.
+ throw new RuntimeException("Not implemented");
+ }
+
+ public StatsEvent[] newArray(int size) {
+ // Purposefully leaving this method not implemented.
+ throw new RuntimeException("Not implemented");
+ }
+ };
+
+ /**
+ * @hide
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mAtomId);
+ out.writeInt(getNumBytes());
+ out.writeByteArray(getBytes());
+ }
+
+ /**
+ * Boilerplate for Parcel.
+ */
+ public int describeContents() {
+ return 0;
+ }
+
}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 05d9167589d4..6b200e1af39a 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -21,6 +21,8 @@ import android.annotation.StringRes;
import android.annotation.TestApi;
import android.graphics.Rect;
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
/**
* Represents a contextual mode of the user interface. Action modes can be used to provide
* alternative interaction modes and replace parts of the normal UI until finished.
@@ -279,6 +281,7 @@ public abstract class ActionMode {
* @return true if the UI used to show this action mode can take focus
* @hide Internal use only
*/
+ @UnsupportedAppUsage
@TestApi
public boolean isUiFocusable() {
return true;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index e95b5caa4fa0..28eb79ae1f2a 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -331,6 +331,7 @@ public final class Choreographer {
* @return the requested time between frames, in milliseconds
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public static long getFrameDelay() {
return sFrameDelay;
@@ -413,6 +414,7 @@ public final class Choreographer {
* @see #removeCallbacks
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
@@ -432,6 +434,7 @@ public final class Choreographer {
* @see #removeCallback
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
@@ -482,6 +485,7 @@ public final class Choreographer {
* @see #postCallbackDelayed
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public void removeCallbacks(int callbackType, Runnable action, Object token) {
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b3d98b8de0a3..03e68b0058b2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -749,20 +749,6 @@ public final class Display {
}
/**
- * @hide
- * Return a rectangle defining the insets of the overscan region of the display.
- * Each field of the rectangle is the number of pixels the overscan area extends
- * into the display on that side.
- */
- public void getOverscanInsets(Rect outRect) {
- synchronized (this) {
- updateDisplayInfoLocked();
- outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
- mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
- }
- }
-
- /**
* Returns the rotation of the screen from its "natural" orientation.
* The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
* (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 7e22dd9f0ac8..38baccbc009f 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -136,30 +136,6 @@ public final class DisplayInfo implements Parcelable {
public int logicalHeight;
/**
- * @hide
- * Number of overscan pixels on the left side of the display.
- */
- public int overscanLeft;
-
- /**
- * @hide
- * Number of overscan pixels on the top side of the display.
- */
- public int overscanTop;
-
- /**
- * @hide
- * Number of overscan pixels on the right side of the display.
- */
- public int overscanRight;
-
- /**
- * @hide
- * Number of overscan pixels on the bottom side of the display.
- */
- public int overscanBottom;
-
- /**
* The {@link DisplayCutout} if present, otherwise {@code null}.
*
* @hide
@@ -322,10 +298,6 @@ public final class DisplayInfo implements Parcelable {
&& largestNominalAppHeight == other.largestNominalAppHeight
&& logicalWidth == other.logicalWidth
&& logicalHeight == other.logicalHeight
- && overscanLeft == other.overscanLeft
- && overscanTop == other.overscanTop
- && overscanRight == other.overscanRight
- && overscanBottom == other.overscanBottom
&& Objects.equals(displayCutout, other.displayCutout)
&& rotation == other.rotation
&& modeId == other.modeId
@@ -365,10 +337,6 @@ public final class DisplayInfo implements Parcelable {
largestNominalAppHeight = other.largestNominalAppHeight;
logicalWidth = other.logicalWidth;
logicalHeight = other.logicalHeight;
- overscanLeft = other.overscanLeft;
- overscanTop = other.overscanTop;
- overscanRight = other.overscanRight;
- overscanBottom = other.overscanBottom;
displayCutout = other.displayCutout;
rotation = other.rotation;
modeId = other.modeId;
@@ -404,10 +372,6 @@ public final class DisplayInfo implements Parcelable {
largestNominalAppHeight = source.readInt();
logicalWidth = source.readInt();
logicalHeight = source.readInt();
- overscanLeft = source.readInt();
- overscanTop = source.readInt();
- overscanRight = source.readInt();
- overscanBottom = source.readInt();
displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
rotation = source.readInt();
modeId = source.readInt();
@@ -452,10 +416,6 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(largestNominalAppHeight);
dest.writeInt(logicalWidth);
dest.writeInt(logicalHeight);
- dest.writeInt(overscanLeft);
- dest.writeInt(overscanTop);
- dest.writeInt(overscanRight);
- dest.writeInt(overscanBottom);
DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
dest.writeInt(rotation);
dest.writeInt(modeId);
@@ -632,17 +592,6 @@ public final class DisplayInfo implements Parcelable {
sb.append(logicalWidth);
sb.append(" x ");
sb.append(logicalHeight);
- if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
- sb.append(", overscan (");
- sb.append(overscanLeft);
- sb.append(",");
- sb.append(overscanTop);
- sb.append(",");
- sb.append(overscanRight);
- sb.append(",");
- sb.append(overscanBottom);
- sb.append(")");
- }
sb.append(", largest app ");
sb.append(largestNominalAppWidth);
sb.append(" x ");
diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl
new file mode 100644
index 000000000000..725cd6f38aaa
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Interface to listen for changes to display window-containers.
+ *
+ * This differs from DisplayManager's DisplayListener:
+ * - onDisplayAdded is always called after the display is actually added to the WM hierarchy.
+ * This corresponds to the DisplayContent and not the raw Dislay from DisplayManager.
+ *
+ * @hide
+ */
+oneway interface IDisplayWindowListener {
+
+ /**
+ * Called when a display is added to the WM hierarchy.
+ */
+ void onDisplayAdded(int displayId);
+
+ /**
+ * Called when a display is removed from the hierarchy.
+ */
+ void onDisplayRemoved(int displayId);
+
+}
diff --git a/core/java/android/view/IDisplayWindowRotationCallback.aidl b/core/java/android/view/IDisplayWindowRotationCallback.aidl
new file mode 100644
index 000000000000..79a15ad746b3
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowRotationCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.view;
+
+import android.view.WindowContainerTransaction;
+
+/**
+ * Interface to be invoked by the controller when it has finished preparing for a display rotation.
+ *
+ * @see IDisplayWindowRotationController
+ * @hide
+ */
+interface IDisplayWindowRotationCallback {
+ void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
+}
diff --git a/core/java/android/view/IDisplayWindowRotationController.aidl b/core/java/android/view/IDisplayWindowRotationController.aidl
new file mode 100644
index 000000000000..c1c7464c3168
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowRotationController.aidl
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.view.IDisplayWindowRotationCallback;
+
+/**
+ * Singular controller of a "remote" display rotation. When a display rotation is started, WM
+ * freezes the screen. It will then call into this controller and wait for a response via the
+ * callback.
+ *
+ * This needs to provide configuration changes because those changes need to be applied in sync
+ * with the actual display rotation to prevent relayouts with mismatched information.
+ *
+ * The flow is like this:
+ * 1. DisplayContent/Rotation freezes the screen
+ * 2. This controller is notified of a rotation and provided a callback.
+ * 3. This controller is responsible for collecting a set of configuration changes to go along with
+ * the rotation.
+ * 4. The callback is fired which tells DisplayContent/Rotation to apply the provided configuration
+ * changes and continue the rotation.
+ *
+ * @hide
+ */
+oneway interface IDisplayWindowRotationController {
+
+ /**
+ * Called when WM needs to know how to update tasks in response to a display rotation.
+ * If this isn't called, a timeout will continue the rotation in WM.
+ *
+ * @param displayId the display that is rotating.
+ * @param fromRotation the rotation the display is rotating from.
+ * @param toRotation the rotation the display is rotating to.
+ * @param callback A callback to be called when this has calculated updated configs.
+ */
+ void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ in IDisplayWindowRotationCallback callback);
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8bf99ec4f251..37b685a23066 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -51,8 +51,8 @@ oneway interface IWindow {
*/
void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
- void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
- in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
+ void resized(in Rect frame, in Rect contentInsets,
+ in Rect visibleInsets, in Rect stableInsets, boolean reportDraw,
in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
in DisplayCutout.ParcelableWrapper displayCutout);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7f717a72b0f9..258b1aef9e3b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,7 +35,9 @@ import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowRotationController;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
@@ -88,8 +90,6 @@ interface IWindowManager
void clearForcedDisplayDensityForUser(int displayId, int userId);
void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
- void setOverscan(int displayId, int left, int top, int right, int bottom);
-
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void setEventDispatching(boolean enabled);
void addWindowToken(IBinder token, int type, int displayId);
@@ -97,6 +97,13 @@ interface IWindowManager
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
/**
+ * Sets a singular remote controller of display rotations. There can only be one. The
+ * controller is called after the display has "frozen" for a rotation and display rotation will
+ * only continue once the controller has finished calculating associated configurations.
+ */
+ void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
+
+ /**
* Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
* used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
* time, so we want to move that off the critical path for starting the new activity.
@@ -476,6 +483,16 @@ interface IWindowManager
void unregisterDisplayFoldListener(IDisplayFoldListener listener);
/**
+ * Registers an IDisplayContainerListener
+ */
+ void registerDisplayWindowListener(IDisplayWindowListener listener);
+
+ /**
+ * Unregisters an IDisplayContainerListener.
+ */
+ void unregisterDisplayWindowListener(IDisplayWindowListener listener);
+
+ /**
* Starts a window trace.
*/
void startWindowTrace();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index eaf6fca1b91f..0489e14993e3 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -43,7 +43,7 @@ import java.util.List;
interface IWindowSession {
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outFrame,
- out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets,
+ out Rect outContentInsets, out Rect outStableInsets,
out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
out InsetsState insetsState);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
@@ -70,9 +70,6 @@ interface IWindowSession {
* @param frameNumber A frame number in which changes requested in this layout will be rendered.
* @param outFrame Rect in which is placed the new position/size on
* screen.
- * @param outOverscanInsets Rect in which is placed the offsets from
- * <var>outFrame</var> in which the content of the window are inside
- * of the display's overlay region.
* @param outContentInsets Rect in which is placed the offsets from
* <var>outFrame</var> in which the content of the window should be
* placed. This can be used to modify the window layout to ensure its
@@ -99,9 +96,9 @@ interface IWindowSession {
*/
int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
- int flags, long frameNumber, out Rect outFrame, out Rect outOverscanInsets,
+ int flags, long frameNumber, out Rect outFrame,
out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
- out Rect outOutsets, out Rect outBackdropFrame,
+ out Rect outBackdropFrame,
out DisplayCutout.ParcelableWrapper displayCutout,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
out InsetsState insetsState);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1fc7f0e36095..75862e01d41c 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -62,19 +62,20 @@ import java.util.Objects;
* {@link Context#getSystemService} to retrieve a standard LayoutInflater instance
* that is already hooked up to the current context and correctly configured
* for the device you are running on.
- *
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
* own views, you can use {@link #cloneInContext} to clone an existing
* ViewFactory, and then call {@link #setFactory} on it to include your
* Factory.
- *
* <p>
* For performance reasons, view inflation relies heavily on pre-processing of
* XML files that is done at build time. Therefore, it is not currently possible
* to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource
* (R.<em>something</em> file.)
+ * <p>
+ * <strong>Note:</strong> This class is <strong>not</strong> thread-safe and a given
+ * instance should only be accessed by a single thread.
*/
@SystemService(Context.LAYOUT_INFLATER_SERVICE)
public abstract class LayoutInflater {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index bd865c063055..be4c598da789 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2610,6 +2610,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* @see #getActionButton()
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public final void setActionButton(int button) {
nativeSetActionButton(mNativePtr, button);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8dd475e0c306..3251127397b6 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -90,7 +90,8 @@ public final class SurfaceControl implements Parcelable {
Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
boolean captureSecureLayers);
private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken,
- long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects);
+ long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects,
+ int format);
private static native long nativeMirrorSurface(long mirrorOfObject);
private static native long nativeCreateTransaction();
private static native long nativeGetNativeTransactionFinalizer();
@@ -196,6 +197,8 @@ public final class SurfaceControl implements Parcelable {
float brightness);
private static native long nativeReadTransactionFromParcel(Parcel in);
private static native void nativeWriteTransactionToParcel(long nativeObject, Parcel out);
+ private static native void nativeSetShadowRadius(long transactionObj, long nativeObject,
+ float shadowRadius);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -1867,8 +1870,27 @@ public final class SurfaceControl implements Parcelable {
*/
public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
float frameScale) {
+ return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
+ }
+
+ /**
+ * Captures a layer and its children and returns a {@link GraphicBuffer} with the content.
+ *
+ * @param layer The root layer to capture.
+ * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
+ * Rect()' or null if no cropping is desired.
+ * @param frameScale The desired scale of the returned buffer; the raw
+ * screen will be scaled up/down.
+ * @param format The desired pixel format of the returned buffer.
+ *
+ * @return Returns a GraphicBuffer that contains the layer capture.
+ * @hide
+ */
+ public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
+ float frameScale, int format) {
final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null);
+ return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null,
+ format);
}
/**
@@ -1883,7 +1905,7 @@ public final class SurfaceControl implements Parcelable {
nativeExcludeObjects[i] = exclude[i].mNativeObject;
}
return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale,
- nativeExcludeObjects);
+ nativeExcludeObjects, PixelFormat.RGBA_8888);
}
/**
@@ -2545,6 +2567,29 @@ public final class SurfaceControl implements Parcelable {
return this;
}
+ /**
+ * Draws shadows of length {@code shadowRadius} around the surface {@link SurfaceControl}.
+ * If the length is 0.0f then the shadows will not be drawn.
+ *
+ * Shadows are drawn around the screen bounds, these are the post transformed cropped
+ * bounds. They can draw over their parent bounds and will be occluded by layers with a
+ * higher z-order. The shadows will respect the surface's corner radius if the
+ * rounded corner bounds (transformed source bounds) are within the screen bounds.
+ *
+ * A shadow will only be drawn on buffer and color layers. If the radius is applied on a
+ * container layer, it will be passed down the hierarchy to be applied on buffer and color
+ * layers but not its children. A scenario where this is useful is when SystemUI animates
+ * a task by controlling a leash to it, can draw a shadow around the app surface by
+ * setting a shadow on the leash. This is similar to how rounded corners are set.
+ *
+ * @hide
+ */
+ public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
+ sc.checkNotReleased();
+ nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius);
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8d0800460775..39202717fc33 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11287,16 +11287,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
|| mAttachInfo == null
- || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
- && !mAttachInfo.mOverscanRequested)) {
+ || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0)) {
outLocalInsets.set(in.getSystemWindowInsetsAsRect());
return in.consumeSystemWindowInsets().inset(outLocalInsets);
} else {
// The application wants to take care of fitting system window for
- // the content... however we still need to take care of any overscan here.
- final Rect overscan = mAttachInfo.mOverscanInsets;
- outLocalInsets.set(overscan);
- return in.inset(outLocalInsets);
+ // the content.
+ outLocalInsets.setEmpty();
+ return in;
}
}
@@ -11376,19 +11374,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Returns the outsets, which areas of the device that aren't a surface, but we would like to
- * treat them as such.
- * @hide
- */
- public void getOutsets(Rect outOutsetRect) {
- if (mAttachInfo != null) {
- outOutsetRect.set(mAttachInfo.mOutsets);
- } else {
- outOutsetRect.setEmpty();
- }
- }
-
- /**
* Returns the visibility status for this view.
*
* @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -24729,6 +24714,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param isRoot true if the view belongs to the root namespace, false
* otherwise
*/
+ @UnsupportedAppUsage
@TestApi
public void setIsRootNamespace(boolean isRoot) {
if (isRoot) {
@@ -28444,13 +28430,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* For windows that are full-screen but using insets to layout inside
- * of the screen areas, these are the current insets to appear inside
- * the overscan area of the display.
- */
- final Rect mOverscanInsets = new Rect();
-
- /**
- * For windows that are full-screen but using insets to layout inside
* of the screen decorations, these are the current insets for the
* content of the window.
*/
@@ -28477,12 +28456,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
/**
- * For windows that include areas that are not covered by real surface these are the outsets
- * for real surface.
- */
- final Rect mOutsets = new Rect();
-
- /**
* In multi-window we force show the system bars. Because we don't want that the surface
* size changes in this mode, we instead have a flag whether the system bars sizes should
* always be consumed, so the app is treated like there are no virtual system bars at all.
@@ -28591,12 +28564,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mHasSystemUiListeners;
/**
- * Set if the window has requested to extend into the overscan region
- * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN.
- */
- boolean mOverscanRequested;
-
- /**
* Set if the visibility of any views has changed.
*/
@UnsupportedAppUsage
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 97adaf57f9b4..8ee7a0ef5a66 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -219,10 +219,6 @@ public final class ViewRootImpl implements ViewParent,
*/
private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
- // properties used by emulator to determine display shape
- public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
- "ro.emu.win_outset_bottom_px";
-
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -447,7 +443,6 @@ public final class ViewRootImpl implements ViewParent,
boolean mIsDrawing;
int mLastSystemUiVisibility;
int mClientWindowLayoutFlags;
- boolean mLastOverscanRequested;
// Pool of queued input events.
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
@@ -507,11 +502,9 @@ public final class ViewRootImpl implements ViewParent,
// These are accessed by multiple threads.
final Rect mWinFrame; // frame given by window manager.
- final Rect mPendingOverscanInsets = new Rect();
final Rect mPendingVisibleInsets = new Rect();
final Rect mPendingStableInsets = new Rect();
final Rect mPendingContentInsets = new Rect();
- final Rect mPendingOutsets = new Rect();
final Rect mPendingBackDropFrame = new Rect();
final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
@@ -900,7 +893,7 @@ public final class ViewRootImpl implements ViewParent,
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
- mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, inputChannel,
+ mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
@@ -921,7 +914,6 @@ public final class ViewRootImpl implements ViewParent,
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
- mPendingOverscanInsets.set(0, 0, 0, 0);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
@@ -1967,12 +1959,6 @@ public final class ViewRootImpl implements ViewParent,
stableInsets = mPendingStableInsets;
displayCutout = mPendingDisplayCutout.get();
}
- Rect outsets = mAttachInfo.mOutsets;
- if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
- contentInsets = new Rect(contentInsets.left + outsets.left,
- contentInsets.top + outsets.top, contentInsets.right + outsets.right,
- contentInsets.bottom + outsets.bottom);
- }
contentInsets = ensureInsetsNonNegative(contentInsets, "content");
stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
mLastWindowInsets = mInsetsController.calculateInsets(
@@ -2146,9 +2132,6 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mInTouchMode = !mAddedTouchMode;
ensureTouchModeLocally(mAddedTouchMode);
} else {
- if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
- insetsChanged = true;
- }
if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
insetsChanged = true;
}
@@ -2163,9 +2146,6 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
+ mAttachInfo.mVisibleInsets);
}
- if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
- insetsChanged = true;
- }
if (mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars) {
insetsChanged = true;
}
@@ -2228,7 +2208,6 @@ public final class ViewRootImpl implements ViewParent,
if (mApplyInsetsRequested) {
mApplyInsetsRequested = false;
- mLastOverscanRequested = mAttachInfo.mOverscanRequested;
dispatchApplyInsets(host);
if (mLayoutRequested) {
// Short-circuit catching a new layout request here, so
@@ -2292,8 +2271,6 @@ public final class ViewRootImpl implements ViewParent,
&& !PixelFormat.formatHasAlpha(params.format)) {
params.format = PixelFormat.TRANSLUCENT;
}
- mAttachInfo.mOverscanRequested =
- (params.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
}
if (mFirst || windowShouldResize || insetsChanged ||
@@ -2342,12 +2319,10 @@ public final class ViewRootImpl implements ViewParent,
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
- + " overscan=" + mPendingOverscanInsets.toShortString()
+ " content=" + mPendingContentInsets.toShortString()
+ " visible=" + mPendingVisibleInsets.toShortString()
+ " stable=" + mPendingStableInsets.toShortString()
+ " cutout=" + mPendingDisplayCutout.get().toString()
- + " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
// If the pending {@link MergedConfiguration} handed back from
@@ -2363,8 +2338,6 @@ public final class ViewRootImpl implements ViewParent,
updatedConfiguration = true;
}
- final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
- mAttachInfo.mOverscanInsets);
contentInsetsChanged = !mPendingContentInsets.equals(
mAttachInfo.mContentInsets);
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
@@ -2373,7 +2346,6 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mStableInsets);
final boolean cutoutChanged = !mPendingDisplayCutout.equals(
mAttachInfo.mDisplayCutout);
- final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
surfaceSizeChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
final boolean alwaysConsumeSystemBarsChanged =
@@ -2389,13 +2361,6 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
+ mAttachInfo.mContentInsets);
}
- if (overscanInsetsChanged) {
- mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
- if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
- + mAttachInfo.mOverscanInsets);
- // Need to relayout with content insets.
- contentInsetsChanged = true;
- }
if (stableInsetsChanged) {
mAttachInfo.mStableInsets.set(mPendingStableInsets);
if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
@@ -2416,12 +2381,8 @@ public final class ViewRootImpl implements ViewParent,
contentInsetsChanged = true;
}
if (contentInsetsChanged || mLastSystemUiVisibility !=
- mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
- || mLastOverscanRequested != mAttachInfo.mOverscanRequested
- || outsetsChanged) {
+ mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
- mLastOverscanRequested = mAttachInfo.mOverscanRequested;
- mAttachInfo.mOutsets.set(mPendingOutsets);
mApplyInsetsRequested = false;
dispatchApplyInsets(host);
// We applied insets so force contentInsetsChanged to ensure the
@@ -4671,12 +4632,10 @@ public final class ViewRootImpl implements ViewParent,
// Recycled in the fall through...
SomeArgs args = (SomeArgs) msg.obj;
if (mWinFrame.equals(args.arg1)
- && mPendingOverscanInsets.equals(args.arg5)
&& mPendingContentInsets.equals(args.arg2)
&& mPendingStableInsets.equals(args.arg6)
&& mPendingDisplayCutout.get().equals(args.arg9)
&& mPendingVisibleInsets.equals(args.arg3)
- && mPendingOutsets.equals(args.arg7)
&& mPendingBackDropFrame.equals(args.arg8)
&& args.arg4 == null
&& args.argi1 == 0
@@ -4706,20 +4665,16 @@ public final class ViewRootImpl implements ViewParent,
}
final boolean framesChanged = !mWinFrame.equals(args.arg1)
- || !mPendingOverscanInsets.equals(args.arg5)
|| !mPendingContentInsets.equals(args.arg2)
|| !mPendingStableInsets.equals(args.arg6)
|| !mPendingDisplayCutout.get().equals(args.arg9)
- || !mPendingVisibleInsets.equals(args.arg3)
- || !mPendingOutsets.equals(args.arg7);
+ || !mPendingVisibleInsets.equals(args.arg3);
setFrame((Rect) args.arg1);
- mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
mPendingStableInsets.set((Rect) args.arg6);
mPendingDisplayCutout.set((DisplayCutout) args.arg9);
mPendingVisibleInsets.set((Rect) args.arg3);
- mPendingOutsets.set((Rect) args.arg7);
mPendingBackDropFrame.set((Rect) args.arg8);
mForceNextWindowRelayout = args.argi1 != 0;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
@@ -7174,8 +7129,8 @@ public final class ViewRootImpl implements ViewParent,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
- mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
+ mTmpFrame, mPendingContentInsets, mPendingVisibleInsets,
+ mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
if (mSurfaceControl.isValid()) {
if (USE_BLAST_BUFFERQUEUE == false) {
@@ -7198,7 +7153,6 @@ public final class ViewRootImpl implements ViewParent,
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame);
- mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
@@ -7493,8 +7447,8 @@ public final class ViewRootImpl implements ViewParent,
}
@UnsupportedAppUsage
- private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ private void dispatchResized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
@@ -7519,7 +7473,6 @@ public final class ViewRootImpl implements ViewParent,
Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(frame);
- mTranslator.translateRectInScreenToAppWindow(overscanInsets);
mTranslator.translateRectInScreenToAppWindow(contentInsets);
mTranslator.translateRectInScreenToAppWindow(visibleInsets);
}
@@ -7530,9 +7483,7 @@ public final class ViewRootImpl implements ViewParent,
args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
args.arg4 = sameProcessCall && mergedConfiguration != null
? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
- args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
- args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
args.argi1 = forceLayout ? 1 : 0;
@@ -8637,15 +8588,15 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ public void resized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
- viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
+ viewAncestor.dispatchResized(frame, contentInsets,
+ visibleInsets, stableInsets, reportDraw, mergedConfiguration,
backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId,
displayCutout);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 742ab77b5068..c62e69cc5ed1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1445,7 +1445,10 @@ public interface WindowManager extends ViewManager {
* position its UI elements with this overscan flag is set:</p>
*
* {@sample development/samples/ApiDemos/res/layout/overscan_activity.xml complete}
+ *
+ * @deprecated Overscan areas aren't set by any Android product anymore.
*/
+ @Deprecated
public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
/**
@@ -1685,6 +1688,7 @@ public interface WindowManager extends ViewManager {
*
* {@hide}
*/
+ @UnsupportedAppUsage
@TestApi
public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
@@ -1842,6 +1846,7 @@ public interface WindowManager extends ViewManager {
* Control flags that are private to the platform.
* @hide
*/
+ @UnsupportedAppUsage
@ViewDebug.ExportedProperty(flagMapping = {
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 403bfda78292..0ff6063d4ae2 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -90,7 +90,7 @@ class WindowlessWindowManager implements IWindowSession {
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets,
+ Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
@@ -140,8 +140,8 @@ class WindowlessWindowManager implements IWindowSession {
@Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
- Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
- Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+ Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
+ Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
State state = null;
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index cd2806a685e7..6a706f5183ce 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -70,6 +70,24 @@ final class TextClassificationSession implements TextClassifier {
}
@Override
+ public ConversationActions suggestConversationActions(ConversationActions.Request request) {
+ checkDestroyed();
+ return mDelegate.suggestConversationActions(request);
+ }
+
+ @Override
+ public TextLanguage detectLanguage(TextLanguage.Request request) {
+ checkDestroyed();
+ return mDelegate.detectLanguage(request);
+ }
+
+ @Override
+ public int getMaxGenerateLinksTextLength() {
+ checkDestroyed();
+ return mDelegate.getMaxGenerateLinksTextLength();
+ }
+
+ @Override
public void onSelectionEvent(SelectionEvent event) {
try {
if (mEventHelper.sanitizeEvent(event)) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index a428feac8806..882e81a823c7 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1267,12 +1267,12 @@ public class NumberPicker extends LinearLayout {
* current value is set to the {@link NumberPicker#getMaxValue()} value.
* </p>
* <p>
- * If the argument is less than the {@link NumberPicker#getMaxValue()} and
+ * If the argument is more than the {@link NumberPicker#getMaxValue()} and
* {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the
* current value is set to the {@link NumberPicker#getMaxValue()} value.
* </p>
* <p>
- * If the argument is less than the {@link NumberPicker#getMaxValue()} and
+ * If the argument is more than the {@link NumberPicker#getMaxValue()} and
* {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the
* current value is set to the {@link NumberPicker#getMinValue()} value.
* </p>
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b1752a47ea93..9fbd48ef302d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1226,9 +1226,9 @@ public class ChooserActivity extends ResolverActivity implements
}
@Override
- protected boolean rebuildList() {
+ protected boolean postRebuildList(boolean rebuildCompleted) {
mChooserListAdapter = (ChooserListAdapter) mAdapter;
- return rebuildListInternal();
+ return postRebuildListInternal(rebuildCompleted);
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1beb1c5e912a..3b352a99526b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -328,9 +328,8 @@ public class ResolverActivity extends Activity implements
boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
mAdapter = createAdapter(this, mIntents, initialIntents, rList,
filterLastUsed, mUseLayoutForBrowsables);
- configureContentView();
- if (rebuildList()) {
+ if (configureContentView()) {
return;
}
@@ -1063,11 +1062,13 @@ public class ResolverActivity extends Activity implements
/**
* Sets up the content view.
+ * @return <code>true</code> if the activity is finishing and creation should halt.
*/
- private void configureContentView() {
+ private boolean configureContentView() {
if (mAdapter == null) {
throw new IllegalStateException("mAdapter cannot be null.");
}
+ boolean rebuildCompleted = mAdapter.rebuildList();
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
@@ -1075,21 +1076,26 @@ public class ResolverActivity extends Activity implements
}
setContentView(mLayoutId);
mAdapterView = findViewById(R.id.resolver_list);
+ return postRebuildList(rebuildCompleted);
}
/**
- * Returns true if the activity is finishing and creation should halt.
- * </p>Subclasses must call rebuildListInternal at the end of rebuildList.
+ * Finishing procedures to be performed after the list has been rebuilt.
+ * </p>Subclasses must call postRebuildListInternal at the end of postRebuildList.
+ * @param rebuildCompleted
+ * @return <code>true</code> if the activity is finishing and creation should halt.
*/
- protected boolean rebuildList() {
- return rebuildListInternal();
+ protected boolean postRebuildList(boolean rebuildCompleted) {
+ return postRebuildListInternal(rebuildCompleted);
}
/**
- * Returns true if the activity is finishing and creation should halt.
+ * Finishing procedures to be performed after the list has been rebuilt.
+ * @param rebuildCompleted
+ * @return <code>true</code> if the activity is finishing and creation should halt.
*/
- final boolean rebuildListInternal() {
- boolean rebuildCompleted = mAdapter.rebuildList();
+ final boolean postRebuildListInternal(boolean rebuildCompleted) {
+
int count = mAdapter.getUnfilteredCount();
// We only rebuild asynchronously when we have multiple elements to sort. In the case where
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index fd3cd42b07a1..da43eddeb0bf 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -277,7 +277,7 @@ public class RuntimeInit {
result.append(System.getProperty("java.vm.version")); // such as 1.1.0
result.append(" (Linux; U; Android ");
- String version = Build.VERSION.RELEASE; // "1.0" or "3.4b5"
+ String version = Build.VERSION.RELEASE_OR_CODENAME; // "1.0" or "3.4b5"
result.append(version.length() > 0 ? version : "1.0");
// add the model for the release build
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index b02563a67503..c33b6dc0bba2 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -236,7 +236,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
ViewGroup mContentRoot;
private Rect mTempRect;
- private Rect mOutsets = new Rect();
// This is the caption view for the window, containing the caption and window control
// buttons. The visibility of this decor depends on the workspace and the window type.
@@ -729,24 +728,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
- getOutsets(mOutsets);
- if (mOutsets.top > 0 || mOutsets.bottom > 0) {
- int mode = MeasureSpec.getMode(heightMeasureSpec);
- if (mode != MeasureSpec.UNSPECIFIED) {
- int height = MeasureSpec.getSize(heightMeasureSpec);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- height + mOutsets.top + mOutsets.bottom, mode);
- }
- }
- if (mOutsets.left > 0 || mOutsets.right > 0) {
- int mode = MeasureSpec.getMode(widthMeasureSpec);
- if (mode != MeasureSpec.UNSPECIFIED) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- width + mOutsets.left + mOutsets.right, mode);
- }
- }
-
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
@@ -785,13 +766,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- getOutsets(mOutsets);
- if (mOutsets.left > 0) {
- offsetLeftAndRight(-mOutsets.left);
- }
- if (mOutsets.top > 0) {
- offsetTopAndBottom(-mOutsets.top);
- }
if (mApplyFloatingVerticalInsets) {
offsetTopAndBottom(mFloatingInsets.top);
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index c8ba0a0e25a2..227ef28cd129 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2378,10 +2378,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
& (~getForcedWindowFlags()));
}
- if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
- setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
- }
-
if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
}
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
deleted file mode 100644
index 5f390be05da5..000000000000
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.android.internal.util;
-
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.view.ViewRootImpl;
-
-/**
- * @hide
- */
-public class ScreenShapeHelper {
- /**
- * Return the bottom pixel window outset of a window given its style attributes.
- * @return An outset dimension in pixels or 0 if no outset should be applied.
- */
- public static int getWindowOutsetBottomPx(Resources resources) {
- if (Build.IS_EMULATOR) {
- return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
- } else {
- return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom);
- }
- }
-}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 7e1f13afc2cb..c7cdc3b51bca 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -49,8 +49,8 @@ public class BaseIWindow extends IWindow.Stub {
}
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw,
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+ Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6417b283f520..01f9d0b0cde5 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2250,6 +2250,26 @@ android_media_AudioSystem_setRttEnabled(JNIEnv *env, jobject thiz, jboolean enab
return (jint) check_AudioSystem_Command(AudioSystem::setRttEnabled(enabled));
}
+static jint
+android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids)
+{
+ if (jPids == NULL) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ pid_t *nPidsArray = (pid_t *)env->GetIntArrayElements(jPids, NULL);
+ std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids));
+ status_t status = AudioSystem::setAudioHalPids(nPids);
+ env->ReleaseIntArrayElements(jPids, nPidsArray, 0);
+ jint jStatus = nativeToJavaStatus(status);
+ return jStatus;
+}
+
+static jboolean
+android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz)
+{
+ return AudioSystem::isCallScreenModeSupported();
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -2328,6 +2348,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
{"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
{"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled},
+ {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
+ {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported},
};
static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 7582cae1a761..4f3f283859b4 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,8 +23,8 @@
namespace {
-int getCanLoadSystemLibraries_native() {
- return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
+bool isDebuggable_native() {
+ return android::GraphicsEnv::getInstance().isDebuggable();
}
void setDriverPathAndSphalLibraries_native(JNIEnv* env, jobject clazz, jstring path,
@@ -94,7 +94,7 @@ void hintActivityLaunch_native(JNIEnv* env, jobject clazz) {
}
const JNINativeMethod g_methods[] = {
- { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
+ { "isDebuggable", "()Z", reinterpret_cast<void*>(isDebuggable_native) },
{ "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native) },
{ "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V", reinterpret_cast<void*>(setGpuStats_native) },
{ "setInjectLayersPrSetDumpable", "()Z", reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native) },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d5cd278063c0..f8a2744fdcb0 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -274,7 +274,7 @@ static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
jlong layerObject, jobject sourceCropObj, jfloat frameScale,
- jlongArray excludeObjectArray) {
+ jlongArray excludeObjectArray, jint format) {
auto layer = reinterpret_cast<SurfaceControl *>(layerObject);
if (layer == NULL) {
@@ -311,8 +311,9 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTok
dataspace = pickDataspaceFromColorMode(colorMode);
}
status_t res = ScreenshotClient::captureChildLayers(layer->getHandle(), dataspace,
- ui::PixelFormat::RGBA_8888, sourceCrop,
- excludeHandles, frameScale, &buffer);
+ static_cast<ui::PixelFormat>(format),
+ sourceCrop, excludeHandles, frameScale,
+ &buffer);
if (res != NO_ERROR) {
return NULL;
}
@@ -545,6 +546,14 @@ static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong transactionObj,
transaction->setLayerStack(ctrl, layerStack);
}
+static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jfloat shadowRadius) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ const auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ transaction->setShadowRadius(ctrl, shadowRadius);
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1308,6 +1317,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetCornerRadius },
{"nativeSetLayerStack", "(JJI)V",
(void*)nativeSetLayerStack },
+ {"nativeSetShadowRadius", "(JJF)V",
+ (void*)nativeSetShadowRadius },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
@@ -1376,7 +1387,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeScreenshot },
{"nativeCaptureLayers",
"(Landroid/os/IBinder;JLandroid/graphics/Rect;"
- "F[J)"
+ "F[JI)"
"Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
(void*)nativeCaptureLayers },
{"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 97dae599f5c2..9e0c35a3b3bc 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2436,4 +2436,9 @@ enum PageId {
// OS: R
INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
+ // OPEN: Settings > Apps and notifications > Special app access > notification access >
+ // an app
+ // CATEGORY: SETTINGS
+ // OS: R
+ NOTIFICATION_ACCESS_DETAIL = 1804;
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 8f084abe71a7..ce2717bb2779 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -126,11 +126,12 @@ message ActivityRecordProto {
optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
optional .com.android.server.wm.IdentifierProto identifier = 2;
optional string state = 3;
- optional bool visible = 4;
+ optional bool visible_requested = 4;
optional bool front_of_task = 5;
optional int32 proc_id = 6;
optional bool translucent = 7;
optional .com.android.server.wm.AppWindowTokenProto app_window_token = 8;
+ optional bool visible = 9;
}
message KeyguardControllerProto {
diff --git a/core/proto/android/server/syncstorageengine.proto b/core/proto/android/server/syncstorageengine.proto
new file mode 100644
index 000000000000..87eb1b3c5d95
--- /dev/null
+++ b/core/proto/android/server/syncstorageengine.proto
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.server.content;
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+/**
+ * Stores relevant information from a DayStats object in SyncStorageEngine.
+ */
+message SyncStatisticsProto {
+
+ message DayStats {
+ optional int32 day = 1; // day of the year - defined by SyncStorageEngine#getCurrentDayLocked()
+ optional int32 success_count = 2;
+ optional int64 success_time = 3; // time since epoch
+ optional int32 failure_count = 4;
+ optional int64 failure_time = 5; // time since epoch
+ }
+
+ repeated DayStats stats = 1;
+}
+
+/**
+ * Stores relevant information from a SyncStatusInfo object.
+ */
+message SyncStatusProto {
+
+ message StatusInfo {
+
+ message Stats {
+ optional int64 total_elapsed_time = 1; // time since epoch
+ optional int32 num_syncs = 2;
+ optional int32 num_failures = 3;
+ optional int32 num_cancels = 4;
+ optional int32 num_source_other = 5;
+ optional int32 num_source_local = 6;
+ optional int32 num_source_poll = 7;
+ optional int32 num_source_user = 8;
+ optional int32 num_source_periodic = 9;
+ optional int32 num_source_feed = 10;
+ }
+
+ message LastEventInfo {
+ optional int64 last_event_time = 1; // time since epoch
+ optional string last_event = 2;
+ }
+
+ // Note: version doesn't need to be stored in proto because of how protos store information but
+ // leaving field number 1 open in case we find a usage for it in the future.
+ optional int32 authority_id = 2;
+ optional int64 last_success_time = 3; // time since epoch
+ optional int32 last_success_source = 4;
+ optional int64 last_failure_time = 5; // time since epoch
+ optional int32 last_failure_source = 6;
+ optional string last_failure_message = 7;
+ optional int64 initial_failure_time = 8; // time since epoch
+ optional bool pending = 9;
+ optional bool initialize = 10;
+ repeated int64 periodic_sync_times = 11; // times since epoch
+ repeated LastEventInfo last_event_info = 12;
+ optional int64 last_today_reset_time = 13; // time since epoch
+ optional Stats total_stats = 14;
+ optional Stats today_stats = 15;
+ optional Stats yesterday_stats = 16;
+ repeated int64 per_source_last_success_times = 17; // times since epoch
+ repeated int64 per_source_last_failure_times = 18; // times since epoch
+ }
+
+ repeated StatusInfo status = 1;
+}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c9a18296a292..23566a6df847 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -235,8 +235,8 @@ message AppWindowTokenProto {
optional WindowContainerThumbnailProto thumbnail = 6;
optional bool fills_parent = 7;
optional bool app_stopped = 8;
- optional bool hidden_requested = 9;
- optional bool client_hidden = 10;
+ optional bool visible_requested = 9;
+ optional bool client_visible = 10;
optional bool defer_hiding_client = 11;
optional bool reported_drawn = 12;
optional bool reported_visible = 13;
@@ -248,8 +248,9 @@ message AppWindowTokenProto {
optional IdentifierProto starting_window = 19;
optional bool starting_displayed = 20;
optional bool starting_moved = 21;
- optional bool hidden_set_from_transferred_starting_window = 22;
+ optional bool visible_set_from_transferred_starting_window = 22;
repeated .android.graphics.RectProto frozen_bounds = 23;
+ optional bool visible = 24;
}
/* represents WindowToken */
@@ -259,7 +260,6 @@ message WindowTokenProto {
optional WindowContainerProto window_container = 1;
optional int32 hash_code = 2;
repeated WindowStateProto windows = 3;
- optional bool hidden = 4;
optional bool waiting_to_show = 5;
optional bool paused = 6;
}
@@ -385,12 +385,12 @@ message WindowFramesProto {
optional .android.graphics.RectProto display_frame = 4;
optional .android.graphics.RectProto frame = 5;
optional .android.graphics.RectProto outset_frame = 6;
- optional .android.graphics.RectProto overscan_frame = 7;
+ optional .android.graphics.RectProto overscan_frame = 7 [deprecated=true];
optional .android.graphics.RectProto parent_frame = 8;
optional .android.graphics.RectProto visible_frame = 9;
optional .android.view.DisplayCutoutProto cutout = 10;
optional .android.graphics.RectProto content_insets = 11;
- optional .android.graphics.RectProto overscan_insets = 12;
+ optional .android.graphics.RectProto overscan_insets = 12 [deprecated=true];
optional .android.graphics.RectProto visible_insets = 13;
optional .android.graphics.RectProto stable_insets = 14;
optional .android.graphics.RectProto outsets = 15;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index d010c8ff8ad9..004b096496db 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -119,6 +119,9 @@ message PackageProto {
// The package that requested the installation of this one.
optional string initiating_package_name = 1;
+
+ // The package on behalf of which the initiiating package requested the install.
+ optional string originating_package_name = 2;
}
// Name of package. e.g. "com.android.providers.telephony".
diff --git a/tests/WindowManagerStressTest/Android.bp b/core/proto/android/stats/textclassifier/Android.bp
index 98749a7e4512..bf9022711206 100644
--- a/tests/WindowManagerStressTest/Android.bp
+++ b/core/proto/android/stats/textclassifier/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2016 The Android Open Source Project
+// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,10 +11,13 @@
// 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: "WindowManagerStressTest",
- srcs: ["**/*.java"],
- platform_apis: true,
-}
+java_library_static {
+ name: "textclassifierprotoslite",
+ proto: {
+ type: "lite",
+ },
+ srcs: [
+ "*.proto",
+ ],
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d70fbcd5fde..9f77407b2391 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2007,7 +2007,7 @@
<eat-comment />
<!-- @SystemApi Allows granting runtime permissions to telephony related components.
- @hide Used internally. -->
+ @hide -->
<permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
android:protectionLevel="signature|telephony" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2b20a6b0360a..485162c13112 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Uitgevee deur jou administrateur"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n·Skakel Donker-tema aan\n·Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Hey Google\", af of beperk hulle"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Skakel aan"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Regstreekse deling is nie beskikbaar nie"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programmelys"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Opneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2588814e7ef3..f0a4307cc9d1 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"እሺ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል\n\n"<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"የባትሪ ዕድሜን ለማራዘም፣ የባትሪ ቆጣቢ፦\n·ጨለማ ገጽታን ያበራል\n·የበስተጀርባ እንቅስቃሴን፣ አንዳንድ የሚታዩ ማሳመሪያዎችን፣ እና ሌሎች እንደ “Hey Google” ያሉ ባህሪያትን ያጠፋል ወይም ይገድባል"</string>
<string name="data_saver_description" msgid="6015391409098303235">"የውሂብ አጠቃቀም እንዲቀንስ ለማገዝ ውሂብ ቆጣቢ አንዳንድ መተግበሪያዎች ከበስተጀርባ ሆነው ውሂብ እንዳይልኩ ወይም እንዳይቀበሉ ይከለክላቸዋል። በአሁኑ ጊዜ እየተጠቀሙበት ያለ መተግበሪያ ውሂብ ሊደርስ ይችላል፣ ነገር ግን ባነሰ ተደጋጋሚነት ሊሆን ይችላል። ይሄ ማለት ለምሳሌ ምስሎችን መታ እስኪያደርጓቸው ድረስ ላይታዩ ይችላሉ ማለት ነው።"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ውሂብ ቆጣቢ ይጥፋ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"አብራ"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ቀጥታ ማጋራት አይገኝም"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"የመተግበሪያዎች ዝርዝር"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ይህ መተግበሪያ የመቅረጽ ፈቃድ አልተሰጠውም፣ ነገር ግን በዚህ ዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅረጽ ይችላል።"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 162c066e8203..4ecf6e7099b6 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1863,10 +1863,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"موافق"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"هل تريد تشغيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"تشغيل"</string>
@@ -2144,4 +2142,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"لا تتوفّر إمكانية المشاركة المباشرة."</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"قائمة التطبيقات"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏لم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 2ae2ad4d4094..81a04b7d83a0 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"পোনপটীয়া শ্বেয়াৰৰ সুবিধা নাই"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"এপ্‌সমূহৰ সূচী"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 2f8cd996f565..9f43c36876c0 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Admin tərəfindən silindi"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət xüsusiyyəti:\n·Qaranlıq temanı aktiv edir\n·Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər xüsusiyyətləri deaktiv edir və ya məhdudlaşdırır"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsini və qəbulunun qarşısını alır. Hazırda istifadə etdiyiniz tətbiq dataya daxil ola bilər, lakin bunu tez-tez edə bilməz. Bu o deməkdir ki, məsələn, Siz üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Data Qənaəti aktiv edilsin?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivləşdirin"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Birbaşa paylaşım əlçatan deyil"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Tətbiq siyahısı"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu tətbiqə yazmaq icazəsi verilməyib, lakin, bu USB vasitəsilə səs yaza bilər."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9c1375822d12..a6ad7331c1d9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je administrator"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Potvrdi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Radi dužeg trajanja baterije, ušteda baterije:\n·uključuje tamnu temu\n·isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2042,4 +2040,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno deljenje nije dostupno"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacija"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ova aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 48ca6df7526d..92cad08ad093 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Выдалены вашым адміністратарам"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n·уключае цёмную тэму;\n·выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"У рэжыме Эканомія трафіка фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Уключыць Эканомію трафіка?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Уключыць"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Непасрэднае абагульванне недаступнае"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Спіс праграм"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"У гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту USB-прыладу."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 1d6e7f1324f7..9a4ca0cff046 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Изтрито от администратора ви"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"С цел удължаване на живота на батерията режимът за запазването й:\n·включва тъмната тема;\n·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string>
<string name="data_saver_description" msgid="6015391409098303235">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ще вкл. ли Икономия на данни?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Включване"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Няма възможност за директно споделяне"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Списък с приложения"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложението няма разрешение за записване, но може да записва звук чрез това USB устройство."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index bdb5572450b6..4dc5f5c897ce 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ঠিক আছে"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n·গাঢ় থিম চালু করে\n·ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"চালু করুন"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"সরাসরি শেয়ার করার সুবিধা নেই"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"অ্যাপের তালিকা"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"এই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 03a4cc5a7457..ea4d20965f29 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1796,10 +1796,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Uredu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2044,4 +2042,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktno dijeljenje nije dostupno"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Spisak aplikacija"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ovoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fd076686089a..4f9eeb8108ee 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Suprimit per l\'administrador"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"D\'acord"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"\n\n"<annotation id="url">"Més informació"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n Activa el tema fosc\n Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activar Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activa"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"La compartició directa no està disponible"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Llista d\'aplicacions"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e2f03df8ad25..502a7a8d1961 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Smazáno administrátorem"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“\n\n"<annotation id="url">"Další informace"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnout Spořič dat?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnout"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Přímé sdílení není k dispozici"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikací"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3916f1e1523f..d347e357c4ae 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet af din administrator"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Batterisparefunktionen gør følgende for at spare på batteriet:\n·Aktiverer Mørkt tema\n·Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå Datasparefunktion til?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Slå til"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Det er ikke muligt at dele direkte"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste over apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 9635b2db35c7..b4b40eabd859 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share nicht verfügbar"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste der Apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Diese App hat noch keine Berechtigung zum Aufnehmen erhalten, könnte aber Audioaufnahmen über dieses USB-Gerät machen."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2766ce4de52b..73828a1296df 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ενημερώθηκε από τον διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Διαγράφηκε από τον διαχειριστή σας"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\".\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n·Ενεργοποιεί το Σκούρο θέμα\n·Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή \"Hey Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ενεργοποίηση"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Η άμεση κοινοποίηση δεν είναι διαθέσιμη"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Λίστα εφαρμογών"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index dba13539b799..9163214f0204 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4ecafc99f51d..dff558f545c3 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index dba13539b799..9163214f0204 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index dba13539b799..9163214f0204 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct share not available"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Apps list"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"This app has not been granted record permission but could capture audio through this USB device."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 331133a17778..7519ad62b9f3 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2006,4 +2006,13 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‎Direct share not available‎‏‎‎‏‎"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎Apps list‎‏‎‎‏‎"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎This app has not been granted record permission but could capture audio through this USB device.‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_home_label" msgid="6089400419441597916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎Home‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_back_label" msgid="8986628898117178971">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎Back‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_recents_label" msgid="7607601657790855723">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎Recent Apps‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_notifications_label" msgid="1578681904050072545">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎Notifications‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_quick_settings_label" msgid="3885565587471448947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎Quick Settings‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_power_dialog_label" msgid="2299530700682199873">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎Power Dialog‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_toggle_split_screen_label" msgid="2853334443686935668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎Toggle Split Screen‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_lock_screen_label" msgid="2377933717780192594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‎Lock Screen‎‏‎‎‏‎"</string>
+ <string name="accessibility_system_action_screenshot_label" msgid="1933564892301816480">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎Screenshot‎‏‎‎‏‎"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f5fc14532acd..038124993179 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Tu administrador actualizó este paquete"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Tu administrador borró este paquete"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n·Activa el Tema oscuro.\n·Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para reducir el uso de datos, Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No está disponible el uso compartido directo"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cfac5dc97add..7f152e1e4e1c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para que la batería dure más, Ahorro de batería:\nActiva el tema oscuro\nDesactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se mostrarán hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"No se puede compartir directamente"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicaciones"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación no tiene permiso para grabar, pero podría registrar audio con este dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8193339615ae..a48c4829b30c 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administraator on selle kustutanud"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Lül. andmemahu säästja sisse?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Lülita sisse"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Vahetu jagamine ei ole saadaval"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Rakenduste loend"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ca79d0525cfa..805df6e97847 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -70,7 +70,7 @@
<string name="ThreeWCMmi" msgid="9051047170321190368">"Hiru hizlaritako deiak"</string>
<string name="RuacMmi" msgid="7827887459138308886">"Nahigabeko dei gogaikarriak ukatzea"</string>
<string name="CndMmi" msgid="3116446237081575808">"Deitzailearen zenbakia ematea"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Ez molestatu"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"Ez molestatzeko modua"</string>
<string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenekin"</string>
<string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenik gabe"</string>
<string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenekin"</string>
@@ -653,8 +653,8 @@
<string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Operadore baten mezularitza-zerbitzuaren goi-mailako interfazeari lotzea baimentzen die erabiltzaileei. Aplikazio normalek ez lukete inoiz beharko."</string>
<string name="permlab_bindCarrierServices" msgid="3233108656245526783">"lotu operadorearen zerbitzuei"</string>
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Operadorearen zerbitzuei lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string>
- <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu \"Ez molestatu\" egoera"</string>
- <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"Ez molestatu\" konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"atzitu ez molestatzeko modua"</string>
+ <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ez molestatzeko moduaren konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
<string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"hasi ikusteko baimena erabiltzen"</string>
<string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Aplikazioaren baimena erabiltzen hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string>
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratzaileak ezabatu du"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Ados"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Bateriaren iraupena luzatzeko, erabili Bateria-aurrezlea:\n·Gai iluna aktibatzen du\n Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Unean erabiltzen ari zaren aplikazioak atzitu egin ahal izango ditu datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Datu-aurrezlea aktibatu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktibatu"</string>
@@ -1813,10 +1811,10 @@
<string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
<string name="zen_mode_alarm" msgid="9128205721301330797">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte (hurrengo alarma)"</string>
<string name="zen_mode_forever" msgid="931849471004038757">"Zuk desaktibatu arte"</string>
- <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"\"Ez molestatu\" desaktibatzen duzun arte"</string>
+ <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Ez molestatzeko modua desaktibatzen duzun arte"</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string>
<string name="toolbar_collapse_description" msgid="2821479483960330739">"Tolestu"</string>
- <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatu"</string>
+ <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ez molestatzeko modua"</string>
<string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Jarduerarik gabeko denbora"</string>
<string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Lanegunetako gaua"</string>
<string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Asteburua"</string>
@@ -1958,10 +1956,10 @@
<string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Dar-dar egingo du deiak eta jakinarazpenak jasotzean"</string>
<string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Ez da joko tonurik deiak eta jakinarazpenak jasotzean"</string>
<string name="notification_channel_system_changes" msgid="5072715579030948646">"Sistema-aldaketak"</string>
- <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatu"</string>
- <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: \"Ez molestatu\" modua jakinarazpenak ezkutatzen ari da"</string>
+ <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Ez molestatzeko modua"</string>
+ <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Berria: Ez molestatzeko modua jakinarazpenak ezkutatzen ari da"</string>
<string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Sakatu informazio gehiago lortzeko eta portaera aldatzeko."</string>
- <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"\"Ez molestatu\" modua aldatu da"</string>
+ <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Ez molestatzeko modua aldatu da"</string>
<string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Sakatu zer dagoen blokeatuta ikusteko."</string>
<string name="notification_app_name_system" msgid="4205032194610042794">"Sistema"</string>
<string name="notification_app_name_settings" msgid="7751445616365753381">"Ezarpenak"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Zuzenean partekatzeko aukera ez dago erabilgarri"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Aplikazioen zerrenda"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a9231e99c5c9..98044c60eaee 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"توسط سرپرست سیستم حذف شد"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"تأیید"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n «طرح زمینه تیره» را روشن می‌کند\n فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n «طرح زمینه تیره» را روشن می‌کند\n فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند"</string>
<string name="data_saver_description" msgid="6015391409098303235">"برای کمک به کاهش مصرف داده، «صرفه‌جویی داده» از ارسال و دریافت داده در پس‌زمینه ازطرف بعضی برنامه‌ها جلوگیری می‌کند. برنامه‌ای که درحال‌حاضر استفاده می‌کنید می‌تواند به داده‌ها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تا زمانی که روی آن‌ها ضربه نزنید نشان داده نمی‌شوند."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"صرفه‌جویی داده روشن شود؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"روشن کردن"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"اشتراک‌گذاری مستقیم دردسترس نیست"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"فهرست برنامه‌ها"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏مجوز ضبط به این برنامه داده نشده است اما می‌تواند صدا را ازطریق این دستگاه USB ضبط کند."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 14ed7b7f8d6f..3476bf52fef3 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Järjestelmänvalvoja poisti tämän."</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Parantaakseen akunkestoa virransäästö\n·ottaa tumman teeman käyttöön\n·poistaa käytöstä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google)."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Otetaanko Data Saver käyttöön?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ota käyttöön"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Suora jakaminen ei käytettävissä"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Sovellusluettelo"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Sovellus ei ole saanut tallennuslupaa mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2c4362d91911..702ecc022932 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n·Activer le thème sombre\n·Désactiver ou limiter l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Hey Google »"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Pour aider à diminuer l\'utilisation des données, la fonction Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activer l\'Économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activer"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index cbb64e6826a6..eb199ded51f1 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Le partage direct n\'est pas disponible"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Liste des applications"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 848cd0b0455a..965997317969 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado polo teu administrador"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Aceptar"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\"\n\n"<annotation id="url">"Máis información"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n·Activa o tema escuro\n·Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para contribuír a reducir o uso de datos, o Economizador de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Queres activar o economizador de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Non está dispoñible a función de compartir directamente"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicacións"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2a5536f31c04..6dab622a29ae 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ઓકે"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n·ઘેરી થીમ ચાલુ કરે છે\n·બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “હેય Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપ્લિકેશનોને પૃષ્ઠભૂમિમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ્લિકેશન ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ચાલુ કરો"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ડાયરેક્ટ શેર કરવાનું ઉપલબ્ધ નથી"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ઍપની સૂચિ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"આ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફતે ઑડિયો કૅપ્ચર કરી શકે છે."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 698a6a749c44..1a082b90f954 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ठीक है"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n·गहरे रंग वाली थीम चालू करता है\n·बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"बैटरी लाइफ़ बढ़ाने के लिए बैटरी सेवर:\n गहरे रंग वाली थीम चालू करता है\nबैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और दूसरी सुविधाएं, जैसे कि \"Hey Google\" को इस्तेमाल करने से रोकता है या बंद करता है"</string>
<string name="data_saver_description" msgid="6015391409098303235">"डेटा खर्च, कम करने के लिए डेटा सेवर कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकता है. आप फ़िलहाल जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा तक पहुंच सकता है लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन्हें टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करें"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधे शेयर नहीं किया जा सकता"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ऐप्लिकेशन की सूची"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"इस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऐसा कर सकता है."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6a134dcf90fa..56d5b2006a95 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisao administrator"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"U redu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Da bi se produljilo trajanje baterije, Štednja baterije:\n·Uključuje Tamnu temu.\n·Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
@@ -2042,4 +2040,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Izravno dijeljenje nije dostupno"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Popis aplikacija"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem ovog USB uređaja."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0cd3fec3c2b7..184b66ae54bb 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"A rendszergazda által törölve"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n Bekapcsolja a sötét témát.\n Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által aktuálisan használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bekapcsolás"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A közvetlen megosztás nem áll rendelkezésre"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Alkalmazások listája"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ez az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a923814c4740..fef6f4e0dc20 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direct Share գործառույթը հասանելի չէ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Հավելվածների ցանկ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Հավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b25b643e31fb..87a88043d337 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Oke"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n·Mengaktifkan Tema gelap\n·Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan kuota, Penghemat Kuota Internet mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Kuota?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Berbagi langsung tidak tersedia"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Daftar aplikasi"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Aplikasi ini tidak diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index c2ffddf69bca..a37eda695c88 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bein deiling er ekki tiltæk"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Forritalisti"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Þetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2e672dc039d4..2b780d0fb4e8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Attiva"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Condivisione diretta non disponibile"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Elenco di app"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fdf34e0898cc..dfbf834a4138 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"נמחקה על ידי מנהל המערכת"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"אישור"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"‏התכונה \'חיסכון בסוללה\':\n·מפעילה עיצוב כהה\n·מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו \"Ok Google\", כדי להאריך את חיי הסוללה"</string>
<string name="data_saver_description" msgid="6015391409098303235">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"‏האם להפעיל את חוסך הנתונים (Data Saver)?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"הפעל"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"שיתוף ישיר אינו זמין"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"רשימת האפליקציות"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏לאפליקציה זו לא ניתנה הרשאת הקלטה, אבל אפשר להקליט אודיו באמצעות התקן ה-USB הזה."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 07c8107e1e05..477698021ea3 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string>
<string name="data_saver_description" msgid="6015391409098303235">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ON にする"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ダイレクト シェアは利用できません"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"アプリのリスト"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"このアプリに録音権限は付与されていませんが、この USB デバイスから音声を収集できるようになります。"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 87bd222a9b6f..7f06b0135366 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"პირდაპირი გაზიარება მიუწვდომელია"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"აპების სია"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b3395dfb3bf6..65da546df2b4 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Әкімші жойған"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Жарайды"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n·Қараңғы тақырыпты іске қосады\n·фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Дерек шығынын азайту үшін Data Saver функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге және алуға жол бермейді. Ашық тұрған қолданба деректерді пайдаланады, бірақ шектеулі шамада (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Data Saver функциясын қосу керек пе?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Қосу"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Тікелей бөлісу мүмкін емес."</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Қолданбалар тізімі"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Қолданбаға жазу рұқсаты берілмеді, бірақ ол осы USB құрылғысы арқылы дыбыс жаза алады."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3eb71f685abd..32b3ee13c439 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1773,10 +1773,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"យល់ព្រម"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំ​ថ្ម៖\n·បើករចនាប័ទ្មងងឹត​\n·បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Hey Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំ​ថ្ម៖\n·បើករចនាប័ទ្មងងឹត​\n·បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Hey Google” ជាដើម"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់​ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យឬ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"បើក"</string>
@@ -2010,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"មិនមាន​ការចែករំលែក​ដោយផ្ទាល់ទេ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"បញ្ជីកម្មវិធី"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"កម្មវិធីនេះ​មិនទាន់បាន​ទទួលសិទ្ធិ​ថតសំឡេង​នៅឡើយទេ ប៉ុន្តែអាច​ថតសំឡេង​តាមរយៈ​ឧបករណ៍ USB នេះបាន។"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index a1d993d9341b..0fab683d3fde 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ಸರಿ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n·ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n·ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ಡೇಟಾ ಉಳಿಸುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ಆನ್‌ ಮಾಡಿ"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ನೇರ ಹಂಚಿಕೆ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index bb1c1e7f4efe..f42a92873694 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"관리자에 의해 업데이트되었습니다."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"관리자에 의해 삭제되었습니다."</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"확인"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n·어두운 테마를 사용 설정합니다.\n·백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다."</string>
<string name="data_saver_description" msgid="6015391409098303235">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"데이터 절약 모드를 사용할까요?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"사용 설정"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"직접 공유가 지원되지 않음"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"앱 목록"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f8191de31af7..82064b2687d4 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1772,10 +1772,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Администраторуңуз жок кылып салган"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ЖАРАЙТ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Батареянын кубатынын мөөнөтүн узартуу үчүн Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n·Түнкү режимди күйгүзөт\n·Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Трафикти үнөмдөө режиминде айрым колдонмолор дайындарды фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайындарды жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Трафикти үнөмдөө режимин иштетесизби?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Күйгүзүү"</string>
@@ -2009,4 +2007,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Түздөн-түз бөлүшүүгө болбойт"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Колдонмолордун тизмеси"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Бул колдонмонун жаздырууга уруксаты жок, бирок бул USB түзмөгү аркылуу аудиону жаздыра алат."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d6150cb47cbd..3aa786e44ecc 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2006,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ບໍ່ສາມາດແບ່ງປັນໂດຍກົງໄດ້"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ລາຍຊື່ແອັບ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ແອັບນີ້ບໍ່ໄດ້ຮັບສິດອະນຸຍາດໃນການບັນທຶກ ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8bcb000c0939..d4d19f4de063 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Ištrynė administratorius"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Gerai"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Kad akumuliatorius veiktų ilgiau, akumuliatoriaus tausojimo priemonė:\n·įjungia tamsiąją temą;\n·išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Hey Google“."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Įj. Duomenų taupymo priemonę?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Įjungti"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiesioginio bendrinimo funkcija nepasiekiama"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Programų sąrašas"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a936bcc5af79..89a98dd57fdc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Labi"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Lai pagarinātu akumulatora darbības ilgumu, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n·Tiek ieslēgts tumšais motīvs.\n·Tiek izslēgtas vai ierobežotas darbības fonā, daži vizuālie efekti un citas funkcijas, piemēram, “Hey Google”."</string>
<string name="data_saver_description" msgid="6015391409098303235">"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="4674073932722787417">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ieslēgt"</string>
@@ -2042,4 +2040,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Tiešā kopīgošana nav pieejama"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lietotņu saraksts"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Šai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index e4bfdf474003..4396c086feed 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1773,10 +1773,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Избришано од администраторот"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Во ред"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n·вклучува темна тема\n·исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“"</string>
<string name="data_saver_description" msgid="6015391409098303235">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Апликацијата што ја користите во моментов можеби ќе пристапува до интернет, но тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Вклучете Штедач на интернет?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Вклучи"</string>
@@ -2010,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Не е достапно директно споделување"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список со апликации"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"На апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 695787955d99..0b3397105c13 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ശരി"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n ഡാർക്ക് തീം ഓണാക്കും\nപശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്‌സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദ‍‍‍ർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ഓണാക്കുക"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"നേരിട്ടുള്ള പങ്കിടൽ ലഭ്യമല്ല"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ആപ്പുകളുടെ ലിസ്‌റ്റ്"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f1077c56dbd3..990a4d0dc21a 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Таны админ устгасан"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч нь:\n·Бараан загварыг асаадаг\n·Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь зарим апп-н өгөгдлийг дэвсгэрт илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Жишээлбэл зургийг товших хүртэл харагдахгүй."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Дата хэмнэгчийг асаах уу?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Асаах"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Шууд хуваалцах боломжгүй"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Аппын жагсаалт"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Энэ апликейшнд бичих зөвшөөрөл олгогдоогүй ч энэ USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 6b17e277c739..edc89a428286 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ओके"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"बॅटरी सेव्‍हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"बॅटरी सेव्‍हर हे बॅटरीचे आयुष्य वाढवते:\n·गडद थीम सुरू करते \n· बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यासारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string>
<string name="data_saver_description" msgid="6015391409098303235">"डेटा सर्व्हर डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अ‍ॅप्सना पार्श्वभूमीमध्ये डेटा पाठवण्यास किंवा मिळवण्यास प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अ‍ॅप डेटा अ‍ॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असा असू शकतो."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा सेव्हर चालू करायचा?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करा"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"थेट शेअर करणे उपलब्ध नाही"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अ‍ॅप्स सूची"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 37d5ef12f09f..0c881c50baf8 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Dipadamkan oleh pentadbir anda"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n·Menghidupkan Tema gelap\n·Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Hey Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Hidupkan"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Perkongsian langsung tidak tersedia"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Senarai apl"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Apl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 8e154b92af93..f5745b519af8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က \n·မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည် \n·နောက်ခံလုပ်ဆောင်ချက် အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် “Hey Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ဒေတာအသုံးပြုမှု ချွေတာမှုစနစ်ကို ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ဖွင့်ပါ"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"တိုက်ရိုက်မျှဝေ၍ မရပါ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"အက်ပ်စာရင်း"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d9d59ea2e094..03597793c0dc 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet av administratoren din"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"For å forlenge batterilevetiden slår Batterisparing\n·på mørkt tema\n·av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå på Datasparing?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Slå på"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Direktedeling er ikke tilgjengelig"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Appliste"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Denne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2b61999b2a4a..2617086bcbd4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2014,4 +2014,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"सीधै आदान प्रदान गर्ने सुविधा उपलब्ध छैन"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"अनुप्रयोगहरूको सूची"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"यो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले यो USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5922388a232a..43b4edecb509 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Verwijderd door je beheerder"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n·Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n Het donkere thema inschakelen\n·Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Databesparing inschakelen?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Inschakelen"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Rechtstreeks delen is niet beschikbaar"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lijst met apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Deze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 04d56524def5..68b76c839540 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ସିଧାସଳଖ ସେୟାର୍ ସୁବିଧା ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ଆପ୍ସ ତାଲିକା"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍‍ଚର୍‍ କରିପାରିବ।"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 2cc004c8bcd6..63b5f53e074d 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ਠੀਕ ਹੈ"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ਚਾਲੂ ਕਰੋ"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ਸਿੱਧਾ ਸਾਂਝਾ ਕਰਨ ਦੀ ਸੁਵਿਧਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ਐਪ ਸੂਚੀ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a5d8125e694d..bd695a9b17e2 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny, \nwyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n włącza tryb ciemny,\n wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Włącz"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Udostępnianie bezpośrednie jest niedostępne"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista aplikacji"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9c44862be565..45a2abd26749 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6a695a797bdd..0fd303fdeedd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu gestor"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado pelo seu gestor"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saber mais"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n·Ativa o tema escuro.\n·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada aplicação que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"A partilha direta não está disponível."</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicações"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Esta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9c44862be565..45a2abd26749 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para aumentar a duração da bateria, a \"Economia de bateria: \n ativa o tema escuro;\n·desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para aumentar a duração da bateria, a \"Economia de bateria\": \n ativa o tema escuro;\n desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ativar Economia de dados?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Ativar"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Compartilhamento direto indisponível"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de apps"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 35ce5d63a4d5..a878628cce10 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Șters de administratorul dvs."</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Pentru a prelungi autonomia bateriei, Economisirea bateriei:\n·activează tema întunecată;\n·activează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Activați Economizorul de date?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activați"</string>
@@ -2042,4 +2040,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Trimiterea directă nu este disponibilă"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista de aplicații"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0fcb4c9a400f..aa94aa6f2bc0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Удалено администратором"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\nвключается тёмная тема;\nотключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string>
<string name="data_saver_description" msgid="6015391409098303235">"В режиме экономии трафика фоновая передача для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Включить"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Функция Direct Share недоступна."</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список приложений"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Приложению не разрешено записывать звук, однако оно может делать это с помощью этого USB-устройства."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index aaff63f9e63d..ee261a54ea95 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1773,10 +1773,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"හරි"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්‍රියාත්මක කරයි\n·පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n·අඳුරු තේමාව ක්‍රියාත්මක කරයි\n·පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string>
<string name="data_saver_description" msgid="6015391409098303235">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"දත්ත සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ක්‍රියාත්මක කරන්න"</string>
@@ -2010,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"ඍජු බෙදා ගැනීම නොලැබේ"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"යෙදුම් ලැයිස්තුව"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්‍රව්‍ය ග්‍රහණය කර ගත හැකිය."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 84b2874ec178..ed4f68c91b99 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Odstránil správca"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“."</string>
<string name="data_saver_description" msgid="6015391409098303235">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Chcete zapnúť šetrič dát?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Zapnúť"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Priame zdieľanie nie je k dispozícii"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Zoznam aplikácií"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Tejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4657001ad8be..dc162a88fa08 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Izbrisal skrbnik"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"V redu"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vklop varčevanja s podatki?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Vklop"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Neposredna skupna raba ni na voljo"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Seznam aplikacij"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ta aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cdef310be9d6..4973f9f1d112 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ndarja e drejtpërdrejtë nuk ofrohet"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Lista e aplikacioneve"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Këtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c953e5ebeb1d..48658bb4922a 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1794,10 +1794,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Избрисао је администратор"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Потврди"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Ради дужег трајања батерије, уштеда батерије:\n·укључује тамну тему\n·искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Укључити Уштеду података?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Укључи"</string>
@@ -2042,4 +2040,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Директно дељење није доступно"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Листа апликација"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ова апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 32cd87893f1c..09a25132ca6e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1414,7 +1414,7 @@
<string name="permission_request_notification_title" msgid="6486759795926237907">"Begärd behörighet"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Begärd behörighet\nför kontot <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="1207197447013960896">"Du använder den här appen i din arbetsprofil"</string>
- <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din profil"</string>
+ <string name="forward_intent_to_work" msgid="621480743856004612">"Du använder den här appen i din jobbprofil"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Indatametod"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Synkronisera"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas\n\n"<annotation id="url">"Läs mer"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"I syfte att förlänga batteritiden sker följande i batterisparläget:\n·mörkt tema aktiveras\n·aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”, inaktiveras eller begränsas"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivera"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Dela direkt är inte tillgängligt"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Applista"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Appen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 15bb4bffc5c8..483c39f81e6c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Imefutwa na msimamizi wako"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Sawa"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n.Huwasha Mandhari meusi\n. Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string>
<string name="data_saver_description" msgid="6015391409098303235">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Ungependa Kuwasha Kiokoa Data?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Washa"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Huwezi kushiriki moja kwa moja"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Orodha ya programu"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Programu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e2629df345ed..0c4e20ee6c1a 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"சரி"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n·டார்க் தீமினை ஆன் செய்யும்\n·“Hey Google” போன்ற பிற அம்சங்கள், பின்னணி செயல்பாடுகள், சில விஷுவல் எஃபெக்ட்கள், ஆகியவற்றை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string>
<string name="data_saver_description" msgid="6015391409098303235">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"இயக்கு"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"நேரடிப் பகிர்வு இல்லை"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ஆப்ஸ் பட்டியல்"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6718470024f2..1b3df6e5f7c9 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"డైరెక్ట్ షేర్ అందుబాటులో లేదు"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"యాప్‌ల జాబితా"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"ఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2f59711b594d..ff1ea21e3c30 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"ลบโดยผู้ดูแลระบบ"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ตกลง"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"เปิด"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"การแชร์โดยตรงไม่พร้อมใช้งาน"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"รายชื่อแอป"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"แอปนี้ไม่ได้รับอนุญาตให้บันทึกเสียงแต่จะบันทึกเสียงผ่านอุปกรณ์ USB นี้ได้"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0fc10142c645..79c040f36d57 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Na-delete ng iyong admin"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n·I-on ang Madilim na tema\n·I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"I-on"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Hindi available ang direktang pagbabahagi"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Listahan ng mga app"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Hindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index f95d8360aae3..d6841f0ac9f3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Yöneticiniz tarafından silindi"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"Tamam"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Pil ömrünü uzatmak için Pil Tasarrufu:\n·Koyu temayı açar\n·Arka plan etkinliğini, bazı görsel efektleri ve \"Hey Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Veri Tasarrufu açılsın mı?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Aç"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Doğrudan paylaşım mevcut değil"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uygulama listesi"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu uygulamaya ses kaydetme izni verilmedi ancak bu USB cihazı üzerinden sesleri yakalayabilir."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d5cdb32de5c0..3412eb2dcc96 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1817,10 +1817,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Видалено адміністратором"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ОК"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google.\n\n"<annotation id="url">"Докладніше"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n·вмикає темну тему;\n·припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти й інші енергозатратні функції, зокрема Ok Google."</string>
<string name="data_saver_description" msgid="6015391409098303235">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Увімкнути Заощадження трафіку?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Увімкнути"</string>
@@ -2076,4 +2074,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Прямий обмін даними недоступний"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Список додатків"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Цей додаток не має дозволу на запис, але він може фіксувати звук через цей USB-пристрій."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index ab2a83cf7304..003fd54e6812 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"ٹھیک ہے"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n گہری تھیم کو آن کرتی ہے\n پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string>
<string name="data_saver_description" msgid="6015391409098303235">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتا ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا پر رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا زیادہ نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"ڈیٹا سیور آن کریں؟"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"آن کریں"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"بلاواسطہ اشتراک دستیاب نہیں ہے"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"ایپس کی فہرست"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"‏اس ایپ کو ریکارڈ کرنے کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ کے ذریعے آڈیو کیپچر کر سکتی ہے۔"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d618d999cdfa..83e99b9abaaa 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n·Tungi mavzuni yoqadi\n·Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Yoqish"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Bevosita ulashuv ishlamaydi"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Ilovalar roʻyxati"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Bu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9880890e5e29..7b17de7d0b83 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Do quản trị viên của bạn xóa"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Để tăng thời lượng pin, Trình tiết kiệm pin:\n·Bật Giao diện tối\n·Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Bật"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Không thể chia sẻ trực tiếp"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Danh sách ứng dụng"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Ứng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1a9eec8d1bfe..e29898fc9fa4 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2008,4 +2008,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"无法使用直接分享功能"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"应用列表"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a69e357e7c35..40f0c9403a10 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"已由您的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"好"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"為延長電池壽命,「省電模式」會:\n開啟深色主題背景\n關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)"</string>
<string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟「數據節省模式」嗎?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法直接分享"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 507f6967c931..2fb155e5aed5 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"確定"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n開啟深色主題\n關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」"</string>
<string name="data_saver_description" msgid="6015391409098303235">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的某個應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"開啟"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"無法使用直接分享功能"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"應用程式清單"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"這個應用程式未取得錄製內容的權限,但可以透過這部 USB 裝置錄製音訊。"</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c15224a81755..2ecc83518318 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1771,10 +1771,8 @@
<string name="package_updated_device_owner" msgid="1847154566357862089">"Kubuyekezwe umlawuli wakho"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Kususwe umlawuli wakho"</string>
<string name="confirm_battery_saver" msgid="639106420541753635">"KULUNGILE"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
- <skip />
- <!-- no translation found for battery_saver_description (2307555792915978653) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"Ukuze unwebise impilo yebhethri, Isilondolozi Sebhethri:\n·Sivula itimu emnyama\n·Sivala noma sikhawulela umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+ <string name="battery_saver_description" msgid="2307555792915978653">"Ukuze unwebise impilo yebhethri, Isilondolozi sebhethri:\n·Vula itimu emnyama\n·Vala noma ukhawulele umsebenzi wangasemuva, eminye imithelela yokubuka, nezinye izici ezifana nokuthi “Hey Google”"</string>
<string name="data_saver_description" msgid="6015391409098303235">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Vula iseva yedatha?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Vula"</string>
@@ -2008,4 +2006,22 @@
<string name="chooser_no_direct_share_targets" msgid="997970693708458895">"Ukwabelana okuqondile akutholakali"</string>
<string name="chooser_all_apps_button_label" msgid="3631524352936289457">"Uhlu lwezinhlelo zokusebenza"</string>
<string name="usb_device_resolve_prompt_warn" msgid="5701272284724577469">"Lolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lungathwebula umsindo ngale divayisi ye-USB."</string>
+ <!-- no translation found for accessibility_system_action_home_label (6089400419441597916) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_back_label (8986628898117178971) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_recents_label (7607601657790855723) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_notifications_label (1578681904050072545) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_quick_settings_label (3885565587471448947) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_power_dialog_label (2299530700682199873) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_toggle_split_screen_label (2853334443686935668) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_lock_screen_label (2377933717780192594) -->
+ <skip />
+ <!-- no translation found for accessibility_system_action_screenshot_label (1933564892301816480) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bad5d6453bda..642dc929e88a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -359,7 +359,9 @@
to {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}. -->
<attr name="windowFullscreen" format="boolean" />
<!-- Flag indicating whether this window should extend into overscan region. Corresponds
- to {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN}. -->
+ to {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN}.
+ @deprecated Overscan areas aren't set by any Android product anymore.
+ -->
<attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
<attr name="windowIsFloating" format="boolean" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index efa42e5735e1..cb0b5993c420 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2652,6 +2652,9 @@
<!-- The amount to scale fullscreen snapshots for Overview and snapshot starting windows. -->
<item name="config_fullTaskSnapshotScale" format="float" type="dimen">1.0</item>
+ <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->
+ <bool name="config_use16BitTaskSnapshotPixelFormat">false</bool>
+
<!-- Determines whether recent tasks are provided to the user. Default device has recents
property. If this is false, then the following recents config flags are ignored. -->
<bool name="config_hasRecents">true</bool>
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index 840a551f914f..64483f1f32db 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -29,9 +29,6 @@
<!-- The alert controller to use for alert dialogs. -->
<integer name="config_alertDialogController">0</integer>
- <!-- True if windowOverscan should be on by default. -->
- <bool name="config_windowOverscanByDefault">false</bool>
-
<!-- True if preference fragment should clip to padding. -->
<bool name="config_preferenceFragmentClipToPadding">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 91a8ba4ca3d2..28809daeaad8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -356,6 +356,7 @@
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="dimen" name="config_fullTaskSnapshotScale" />
+ <java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
<java-symbol type="bool" name="config_lowRamTaskSnapshotsAndRecents" />
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="string" name="config_recentsComponentName" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 78d218f9a438..f3905e93a525 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -162,7 +162,6 @@ please see themes_device_defaults.xml.
<item name="windowFrame">@null</item>
<item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
<item name="windowFullscreen">false</item>
- <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -536,7 +535,6 @@ please see themes_device_defaults.xml.
<item name="windowFrame">@null</item>
<item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
<item name="windowFullscreen">false</item>
- <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -963,10 +961,11 @@ please see themes_device_defaults.xml.
<!-- Variant of the material (dark) theme that has no title bar and fills
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
+ to true.
+ @deprecated Overscan areas aren't set by any Android product anymore.
+ -->
<style name="Theme.Material.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
- <item name="windowOverscan">true</item>
<item name="windowContentOverlay">@null</item>
</style>
@@ -996,10 +995,11 @@ please see themes_device_defaults.xml.
<!-- Variant of the material (light) theme that has no title bar and fills
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
+ to true.
+ @deprecated Overscan areas aren't set by any Android product anymore.
+ -->
<style name="Theme.Material.Light.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
- <item name="windowOverscan">true</item>
<item name="windowContentOverlay">@null</item>
</style>
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index decc76869a53..2295eb989108 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -60,7 +60,7 @@ public class BuildTest extends TestCase {
assertNotEmpty("BRAND", Build.BRAND);
assertNotEmpty("MODEL", Build.MODEL);
assertNotEmpty("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL);
- assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE);
+ assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE_OR_CODENAME);
assertNotEmpty("TYPE", Build.TYPE);
Assert.assertNotNull("TAGS", Build.TAGS); // TAGS is allowed to be empty.
assertNotEmpty("FINGERPRINT", Build.FINGERPRINT);
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index c2fa8b2b38da..17fe61d879f3 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -32,7 +32,6 @@ import android.text.SpannableString;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.google.common.truth.Truth;
@@ -43,6 +42,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collections;
@@ -54,10 +54,19 @@ import java.util.List;
* Tests are skipped if such a textclassifier does not exist.
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class TextClassifierTest {
+ private static final String LOCAL = "local";
+ private static final String SESSION = "session";
- // TODO: Implement TextClassifierService testing.
+ // TODO: Add SYSTEM, which tests TextClassifier.SYSTEM.
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<Object> textClassifierTypes() {
+ return Arrays.asList(LOCAL, SESSION);
+ }
+
+ @Parameterized.Parameter
+ public String mTextClassifierType;
private static final TextClassificationConstants TC_CONSTANTS =
new TextClassificationConstants(() -> "");
@@ -72,7 +81,17 @@ public class TextClassifierTest {
public void setup() {
mContext = InstrumentationRegistry.getTargetContext();
mTcm = mContext.getSystemService(TextClassificationManager.class);
- mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
+
+ if (mTextClassifierType.equals(LOCAL)) {
+ mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
+ } else {
+ mClassifier = mTcm.createTextClassificationSession(
+ new TextClassificationContext.Builder(
+ "android",
+ TextClassifier.WIDGET_TYPE_NOTIFICATION)
+ .build(),
+ mTcm.getTextClassifier(TextClassifier.LOCAL));
+ }
}
@Test
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index 72be9f5e7eb5..1882c3f8c4c8 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -34,6 +34,7 @@
<permission name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE" />
<permission name="android.permission.MASTER_CLEAR"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 77b0dba67be5..d2ce4e0a03b9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -95,6 +95,9 @@ applications that come with the platform
<privapp-permissions package="com.android.mtp">
<permission name="android.permission.ACCESS_MTP"/>
<permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
<privapp-permissions package="com.android.musicfx">
@@ -207,6 +210,7 @@ applications that come with the platform
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WATCH_APPOPS"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
</privapp-permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 7da2752ab3dd..3c89bfd43f17 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -55,6 +55,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-2006946193": {
+ "message": "setClientVisible: %s clientVisible=%b Callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-2002500255": {
"message": "Defer removing snapshot surface in %dms",
"level": "VERBOSE",
@@ -73,18 +79,18 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1976550065": {
+ "message": "commitVisibility: %s: visible=%b visibleRequested=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-1963461591": {
"message": "Removing %s from %s",
"level": "VERBOSE",
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1958209312": {
- "message": "Clear freezing of %s: hidden=%b freezing=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1953668890": {
"message": "Can't start recents animation, nextAppTransition=%s",
"level": "DEBUG",
@@ -307,12 +313,6 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-1456549051": {
- "message": "setClientHidden: %s clientHidden=%b Callers=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1455600136": {
"message": "Attempted to add Dream window with unknown token %s. Aborting.",
"level": "WARN",
@@ -547,12 +547,6 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
- "-931184679": {
- "message": "Changing app %s hidden=%b performLayout=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-928291778": {
"message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
"level": "VERBOSE",
@@ -841,6 +835,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
+ "-374767836": {
+ "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-371630969": {
"message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
"level": "VERBOSE",
@@ -1207,12 +1207,6 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "358613119": {
- "message": "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"371641947": {
"message": "Window Manager Crash %s",
"level": "WTF",
@@ -1273,6 +1267,12 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "466506262": {
+ "message": "Clear freezing of %s: visible=%b freezing=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"474000473": {
"message": "No stack above target stack=%s",
"level": "DEBUG",
@@ -1357,12 +1357,6 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/Session.java"
},
- "609651209": {
- "message": "addChild: %s at top.",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ADD_REMOVE",
- "at": "com\/android\/server\/wm\/TaskRecord.java"
- },
"620368427": {
"message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
"level": "INFO",
@@ -1495,6 +1489,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "841702299": {
+ "message": "Changing app %s visible=%b performLayout=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"845234215": {
"message": "App is requesting an orientation, return %d for display id=%d",
"level": "VERBOSE",
@@ -1507,12 +1507,6 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
- "857751535": {
- "message": "commitVisibility: %s: hidden=%b hiddenRequested=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"873914452": {
"message": "goodToGo()",
"level": "DEBUG",
@@ -1681,6 +1675,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "1330804250": {
+ "message": "addChild: %s at top.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ADD_REMOVE",
+ "at": "com\/android\/server\/wm\/Task.java"
+ },
"1331177619": {
"message": "Attempted to add a toast window with unknown token %s. Aborting.",
"level": "WARN",
@@ -1903,6 +1903,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1746778201": {
+ "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1747941491": {
"message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s",
"level": "INFO",
@@ -1993,12 +1999,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "1966564525": {
- "message": "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
- "level": "INFO",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"1984470582": {
"message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
"level": "DEBUG",
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 538319c3f1d7..a7e17d13c9e1 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -55,8 +55,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import javax.security.auth.x500.X500Principal;
@@ -811,27 +811,22 @@ public final class KeyChain {
throw new NullPointerException("context == null");
}
ensureNotOnMainThread(context);
- final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ final AtomicReference<IKeyChainService> keyChainService = new AtomicReference<>();
ServiceConnection keyChainServiceConnection = new ServiceConnection() {
volatile boolean mConnectedAtLeastOnce = false;
@Override public void onServiceConnected(ComponentName name, IBinder service) {
if (!mConnectedAtLeastOnce) {
mConnectedAtLeastOnce = true;
- try {
- q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
- } catch (InterruptedException e) {
- // will never happen, since the queue starts with one available slot
- }
+ keyChainService.set(
+ IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
+ countDownLatch.countDown();
}
}
@Override public void onBindingDied(ComponentName name) {
if (!mConnectedAtLeastOnce) {
mConnectedAtLeastOnce = true;
- try {
- q.put(null);
- } catch (InterruptedException e) {
- // will never happen, since the queue starts with one available slot
- }
+ countDownLatch.countDown();
}
}
@Override public void onServiceDisconnected(ComponentName name) {}
@@ -843,7 +838,8 @@ public final class KeyChain {
intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
throw new AssertionError("could not bind to KeyChainService");
}
- IKeyChainService service = q.take();
+ countDownLatch.await();
+ IKeyChainService service = keyChainService.get();
if (service != null) {
return new KeyChainConnection(context, keyChainServiceConnection, service);
} else {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ee8cc40622f8..3c4783590c16 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -1067,6 +1067,17 @@ public class KeyStore {
return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
}
+ /**
+ * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
+ */
+ public void onUserLockedStateChanged(int userHandle, boolean locked) {
+ try {
+ mBinder.onKeyguardVisibilityChanged(locked, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to update user locked state " + userHandle, e);
+ }
+ }
+
private class KeyAttestationCallbackResult {
private KeystoreResponse keystoreResponse;
private KeymasterCertificateChain certificateChain;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 234615d9c81d..2cdd00049242 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.security.KeyStore;
import android.security.keymaster.ExportResult;
@@ -52,8 +53,9 @@ import javax.crypto.Mac;
*
* @hide
*/
+@SystemApi
public class AndroidKeyStoreProvider extends Provider {
- public static final String PROVIDER_NAME = "AndroidKeyStore";
+ private static final String PROVIDER_NAME = "AndroidKeyStore";
// IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
// classes when this provider is instantiated and installed early on during each app's
@@ -68,6 +70,7 @@ public class AndroidKeyStoreProvider extends Provider {
private static final String DESEDE_SYSTEM_PROPERTY =
"ro.hardware.keystore_desede";
+ /** @hide **/
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -111,6 +114,7 @@ public class AndroidKeyStoreProvider extends Provider {
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
+ * @hide
*/
public static void install() {
Provider[] providers = Security.getProviders();
@@ -156,6 +160,7 @@ public class AndroidKeyStoreProvider extends Provider {
* @throws IllegalArgumentException if the provided primitive is not supported or is not backed
* by AndroidKeyStore provider.
* @throws IllegalStateException if the provided primitive is not initialized.
+ * @hide
*/
@UnsupportedAppUsage
public static long getKeyStoreOperationHandle(Object cryptoPrimitive) {
@@ -183,6 +188,7 @@ public class AndroidKeyStoreProvider extends Provider {
return ((KeyStoreCryptoOperation) spi).getOperationHandle();
}
+ /** @hide **/
@NonNull
public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
@NonNull String alias,
@@ -279,6 +285,7 @@ public class AndroidKeyStoreProvider extends Provider {
privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
}
+ /** @hide **/
@NonNull
public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
@NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -300,6 +307,7 @@ public class AndroidKeyStoreProvider extends Provider {
return new KeyPair(publicKey, privateKey);
}
+ /** @hide **/
@NonNull
public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
@NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -318,6 +326,7 @@ public class AndroidKeyStoreProvider extends Provider {
return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
}
+ /** @hide **/
@NonNull
public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
@NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
@@ -357,6 +366,7 @@ public class AndroidKeyStoreProvider extends Provider {
return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
}
+ /** @hide **/
@NonNull
public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
@NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
@@ -390,7 +400,9 @@ public class AndroidKeyStoreProvider extends Provider {
*
* <p>Note: the returned {@code KeyStore} is already initialized/loaded. Thus, there is
* no need to invoke {@code load} on it.
+ * @hide
*/
+ @SystemApi
@NonNull
public static java.security.KeyStore getKeyStoreForUid(int uid)
throws KeyStoreException, NoSuchProviderException {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index bd6ce7ec6a3b..6df3b8c7661e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -19,6 +19,7 @@ package android.security.keystore;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.KeyguardManager;
@@ -808,10 +809,14 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
/**
* Sets the UID which will own the key.
*
+ * Such cross-UID access is permitted to a few system UIDs and only to a few other UIDs
+ * (e.g., Wi-Fi, VPN) all of which are system.
+ *
* @param uid UID or {@code -1} for the UID of the current process.
*
* @hide
*/
+ @SystemApi
@NonNull
public Builder setUid(int uid) {
mUid = uid;
@@ -1256,6 +1261,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*
* Sets whether to include a temporary unique ID field in the attestation certificate.
*/
+ @UnsupportedAppUsage
@TestApi
@NonNull
public Builder setUniqueIdIncluded(boolean uniqueIdIncluded) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 826a8ea09d7e..f0867686c321 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -147,7 +147,6 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
mNativeSurface = new ReliableSurface{std::move(surface)};
// TODO: Fix error handling & re-shorten timeout
ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
- mNativeSurface->enableFrameTimestamps(true);
} else {
mNativeSurface = nullptr;
}
@@ -169,6 +168,10 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
if (hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
+ // Enable frame stats after the surface has been bound to the appropriate graphics API.
+ // Order is important when new and old surfaces are the same, because old surface has
+ // its frame stats disabled automatically.
+ mNativeSurface->enableFrameTimestamps(true);
} else {
mRenderThread.removeFrameCallback(this);
mGenerationID++;
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index 1b9939d9a598..b0fad57dfd29 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -22,6 +22,7 @@ cc_library_shared {
"src/os/DropBoxManager.cpp",
"src/os/StatsDimensionsValue.cpp",
"src/os/StatsLogEventWrapper.cpp",
+ "src/util/StatsEvent.cpp",
],
shared_libs: [
diff --git a/libs/services/include/android/util/StatsEvent.h b/libs/services/include/android/util/StatsEvent.h
new file mode 100644
index 000000000000..48631174f7dd
--- /dev/null
+++ b/libs/services/include/android/util/StatsEvent.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef STATS_EVENT_H
+#define STATS_EVENT_H
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <vector>
+
+namespace android {
+namespace util {
+class StatsEvent : public android::Parcelable {
+ public:
+ StatsEvent();
+
+ StatsEvent(StatsEvent&& in) = default;
+
+ android::status_t writeToParcel(android::Parcel* out) const;
+
+ android::status_t readFromParcel(const android::Parcel* in);
+
+ private:
+ int mAtomTag;
+ std::vector<uint8_t> mBuffer;
+};
+} // Namespace util
+} // Namespace android
+
+#endif // STATS_ EVENT_H \ No newline at end of file
diff --git a/libs/services/src/util/StatsEvent.cpp b/libs/services/src/util/StatsEvent.cpp
new file mode 100644
index 000000000000..8b8579167b00
--- /dev/null
+++ b/libs/services/src/util/StatsEvent.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android/util/StatsEvent.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <vector>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+using std::vector;
+
+namespace android {
+namespace util {
+
+StatsEvent::StatsEvent(){};
+
+status_t StatsEvent::writeToParcel(Parcel* out) const {
+ // Implement me if desired. We don't currently use this.
+ ALOGE("Cannot do c++ StatsEvent.writeToParcel(); it is not implemented.");
+ (void)out; // To prevent compile error of unused parameter 'out'
+ return UNKNOWN_ERROR;
+};
+
+status_t StatsEvent::readFromParcel(const Parcel* in) {
+ status_t res = OK;
+ if (in == NULL) {
+ ALOGE("statsd received parcel argument was NULL.");
+ return BAD_VALUE;
+ }
+ if ((res = in->readInt32(&mAtomTag)) != OK) {
+ ALOGE("statsd could not read atom tag from parcel");
+ return res;
+ }
+ if ((res = in->readByteVector(&mBuffer)) != OK) {
+ ALOGE("statsd could not read buffer from parcel");
+ return res;
+ }
+ return NO_ERROR;
+};
+
+} // Namespace util
+} // Namespace android
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
deleted file mode 100644
index 2f386271dcb7..000000000000
--- a/location/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsLocationCoarseTestCases"
- },
- {
- "name": "CtsLocationNoneTestCases"
- }
- ]
-}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 211a0cb5852d..b363686c2df5 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -27,7 +27,11 @@ import java.lang.annotation.RetentionPolicy;
* This class is used in conjunction with the {@link GnssStatus.Callback}.
*/
public final class GnssStatus {
+
// these must match the definitions in gps.h
+ //
+ // Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support
+ // library. if adding a constellation, please update that file as well.
/** Unknown constellation type. */
public static final int CONSTELLATION_UNKNOWN = 0;
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index c48f6e83ff20..39a7e25cb68b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -435,7 +435,7 @@ public class LocationManager {
* {@link SecurityException} if the location permissions were not sufficient to use the
* specified provider.
*
- * @param provider the name of the provider
+ * @param provider a provider listed by {@link #getAllProviders()}
* @return true if the provider exists and is enabled
*
* @throws IllegalArgumentException if provider is null
@@ -453,7 +453,7 @@ public class LocationManager {
* {@link SecurityException} if the location permissions were not sufficient to use the
* specified provider.
*
- * @param provider the name of the provider
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param userHandle the user to query
* @return true if the provider exists and is enabled
*
@@ -477,8 +477,8 @@ public class LocationManager {
* functions as a best effort. It should not be relied on in any meaningful sense as providers
* may no longer be enabled or disabled by clients.
*
- * @param provider the name of the provider
- * @param enabled true to enable the provider. false to disable the provider
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param enabled whether to enable or disable the provider
* @param userHandle the user to set
* @return true if the value was set, false otherwise
*
@@ -534,7 +534,7 @@ public class LocationManager {
* will always attempt to return a current location, but will potentially use additional power
* in the course of the attempt as compared to this method.
*
- * @param provider the name of the provider
+ * @param provider a provider listed by {@link #getAllProviders()}
* @return the last known location for the given provider, or null if not available
* @throws SecurityException if no suitable permission is present
* @throws IllegalArgumentException if provider is null or doesn't exist
@@ -587,7 +587,7 @@ public class LocationManager {
* determine a valid location fix more often than while in the foreground. Background
* applications may be throttled in their location accesses to some degree.
*
- * @param provider the name of the provider with which to register
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param cancellationSignal an optional signal that allows for cancelling this call
* @param executor the callback will take place on this {@link Executor}
* @param consumer the callback invoked with either a {@link Location} or null
@@ -667,7 +667,7 @@ public class LocationManager {
* <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for
* more detail on how to use this method.
*
- * @param provider the name of the provider with which to register
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param listener the listener to receive location updates
* @param looper the looper handling listener callbacks, or null to use the looper of the
* calling thread
@@ -729,7 +729,7 @@ public class LocationManager {
* <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
* on how to use this method.
*
- * @param provider the name of the provider with which to register
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param pendingIntent the pending intent to send location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
@@ -829,10 +829,10 @@ public class LocationManager {
*
* <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
*
- * @param provider the name of the provider with which to register
- * @param minTimeMs minimum time interval between location updates in milliseconds
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
- * @param listener the listener to receive location updates
+ * @param listener the listener to receive location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if listener is null
@@ -857,12 +857,12 @@ public class LocationManager {
* <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
* for more detail on how this method works.
*
- * @param provider the name of the provider with which to register
- * @param minTimeMs minimum time interval between location updates in milliseconds
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
- * @param listener the listener to receive location updates
- * @param looper the looper handling listener callbacks, or null to use the looper of the
- * calling thread
+ * @param listener the listener to receive location updates
+ * @param looper the looper handling listener callbacks, or null to use the looper of the
+ * calling thread
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if listener is null
@@ -886,11 +886,11 @@ public class LocationManager {
* <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
* for more detail on how this method works.
*
- * @param provider the name of the provider with which to register
- * @param minTimeMs minimum time interval between location updates in milliseconds
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param minTimeMs minimum time interval between location updates in milliseconds
* @param minDistanceM minimum distance between location updates in meters
- * @param executor the executor handling listener callbacks
- * @param listener the listener to receive location updates
+ * @param executor the executor handling listener callbacks
+ * @param listener the listener to receive location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
* @throws IllegalArgumentException if executor is null
@@ -980,9 +980,9 @@ public class LocationManager {
* <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
* for more detail on how this method works.
*
- * @param provider the name of the provider with which to register
- * @param minTimeMs minimum time interval between location updates in milliseconds
- * @param minDistanceM minimum distance between location updates in meters
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param minTimeMs minimum time interval between location updates in milliseconds
+ * @param minDistanceM minimum distance between location updates in meters
* @param pendingIntent the pending intent to send location updates
*
* @throws IllegalArgumentException if provider is null or doesn't exist
@@ -1317,7 +1317,7 @@ public class LocationManager {
* Returns the information about the location provider with the given name, or null if no
* provider exists by that name.
*
- * @param provider the provider name
+ * @param provider a provider listed by {@link #getAllProviders()}
* @return location provider information, or null if provider does not exist
*
* @throws IllegalArgumentException if provider is null
@@ -1374,7 +1374,7 @@ public class LocationManager {
* Sends additional commands to a location provider. Can be used to support provider specific
* extensions to the Location Manager API.
*
- * @param provider name of the location provider
+ * @param provider a provider listed by {@link #getAllProviders()}
* @param command name of the command to send to the provider
* @param extras optional arguments for the command, or null
* @return true always, the return value may be ignored
@@ -1810,6 +1810,14 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
+ UnsupportedOperationException ex = new UnsupportedOperationException(
+ "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
+ throw ex;
+ } else {
+ Log.w(TAG, ex);
+ }
+
if (status == null) {
status = new GpsStatus();
}
@@ -1837,8 +1845,8 @@ public class LocationManager {
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
UnsupportedOperationException ex = new UnsupportedOperationException(
- "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
- if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+ "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
throw ex;
} else {
Log.w(TAG, ex);
@@ -1862,8 +1870,8 @@ public class LocationManager {
@Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
UnsupportedOperationException ex = new UnsupportedOperationException(
- "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
- if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+ "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
throw ex;
} else {
Log.w(TAG, ex);
@@ -1955,23 +1963,21 @@ public class LocationManager {
/**
* No-op method to keep backward-compatibility.
*
- * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead.
- * @removed
+ * @deprecated Use {@link #addNmeaListener} instead.
*/
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
- public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+ public boolean addNmeaListener(@NonNull GpsStatus.NmeaListener listener) {
return false;
}
/**
* No-op method to keep backward-compatibility.
*
- * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
- * @removed
+ * @deprecated Use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
*/
@Deprecated
- public void removeNmeaListener(GpsStatus.NmeaListener listener) {}
+ public void removeNmeaListener(@NonNull GpsStatus.NmeaListener listener) {}
/**
* Adds an NMEA listener.
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ac5a9f82bcd0..3a092a043af6 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -710,7 +710,7 @@ public final class AudioAttributes implements Parcelable {
* @return the same Builder instance.
*/
public Builder setFlags(int flags) {
- flags &= AudioAttributes.FLAG_ALL;
+ flags &= AudioAttributes.FLAG_ALL_PUBLIC;
mFlags |= flags;
return this;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9ad7f2a7dcc6..d5524915f423 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1,4 +1,5 @@
/*
+/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -1931,12 +1932,11 @@ public class AudioManager {
* application when it places a phone call, as it will cause signals from the radio layer
* to feed the platform mixer.
*
- * @param mode the requested audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE},
- * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}).
+ * @param mode the requested audio mode.
* Informs the HAL about the current audio state so that
* it can route the audio appropriately.
*/
- public void setMode(int mode) {
+ public void setMode(@AudioMode int mode) {
final IAudioService service = getService();
try {
service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
@@ -1948,14 +1948,47 @@ public class AudioManager {
/**
* Returns the current audio mode.
*
- * @return the current audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE},
- * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}).
- * Returns the current current audio state from the HAL.
+ * @return the current audio mode.
*/
+ @AudioMode
public int getMode() {
final IAudioService service = getService();
try {
- return service.getMode();
+ int mode = service.getMode();
+ int sdk;
+ try {
+ sdk = getContext().getApplicationInfo().targetSdkVersion;
+ } catch (NullPointerException e) {
+ // some tests don't have a Context
+ sdk = Build.VERSION.SDK_INT;
+ }
+ if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
+ mode = MODE_IN_CALL;
+ }
+ return mode;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Indicates if the platform supports a special call screening and call monitoring mode.
+ * <p>
+ * When this mode is supported, it is possible to perform call screening and monitoring
+ * functions while other use cases like music or movie playback are active.
+ * <p>
+ * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
+ * call screening mode.
+ * <p>
+ * If call screening mode is not supported, setting mode to
+ * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
+ * {@link #getMode()}.
+ * @return true if call screening mode is supported, false otherwise.
+ */
+ public boolean isCallScreeningModeSupported() {
+ final IAudioService service = getService();
+ try {
+ return service.isCallScreeningModeSupported();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1989,6 +2022,22 @@ public class AudioManager {
* In communication audio mode. An audio/video chat or VoIP call is established.
*/
public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
+ /**
+ * Call screening in progress. Call is connected and audio is accessible to call
+ * screening applications but other audio use cases are still possible.
+ */
+ public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
+
+ /** @hide */
+ @IntDef(flag = false, prefix = "MODE_", value = {
+ MODE_NORMAL,
+ MODE_RINGTONE,
+ MODE_IN_CALL,
+ MODE_IN_COMMUNICATION,
+ MODE_CALL_SCREENING }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioMode {}
/* Routing bits for setRouting/getRouting API */
/**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index bb731a8189f9..a3a87774483b 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -132,7 +132,8 @@ public class AudioSystem
public static final int MODE_RINGTONE = 1;
public static final int MODE_IN_CALL = 2;
public static final int MODE_IN_COMMUNICATION = 3;
- public static final int NUM_MODES = 4;
+ public static final int MODE_CALL_SCREENING = 4;
+ public static final int NUM_MODES = 5;
public static String modeToString(int mode) {
switch (mode) {
@@ -142,6 +143,7 @@ public class AudioSystem
case MODE_INVALID: return "MODE_INVALID";
case MODE_NORMAL: return "MODE_NORMAL";
case MODE_RINGTONE: return "MODE_RINGTONE";
+ case MODE_CALL_SCREENING: return "MODE_CALL_SCREENING";
default: return "unknown mode (" + mode + ")";
}
}
@@ -1124,6 +1126,17 @@ public class AudioSystem
*/
public static native boolean isHapticPlaybackSupported();
+ /**
+ * Send audio HAL server process pids to native audioserver process for use
+ * when generating audio HAL servers tombstones
+ */
+ public static native int setAudioHalPids(int[] pids);
+
+ /**
+ * @see AudioManager#isCallScreeningModeSupported()
+ */
+ public static native boolean isCallScreeningModeSupported();
+
// Items shared with audio service
/**
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d6a4ea7cb39f..da8e402ffb9f 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -237,11 +237,56 @@ public class ExifInterface {
public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
/** Type is String. */
public static final String TAG_OECF = "OECF";
- /** Type is String. {@hide} */
+ /**
+ * <p>A tag used to record the offset from UTC (the time difference from Universal Time
+ * Coordinated including daylight saving time) of the time of DateTime tag. The format when
+ * recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+ * the offsets are unknown, all the character spaces except colons (":") should be filled
+ * with blank characters, or else the Interoperability field should be filled with blank
+ * characters. The character string length is 7 Bytes including NULL for termination. When
+ * the field is left blank, it is treated as unknown.</p>
+ *
+ * <ul>
+ * <li>Tag = 36880</li>
+ * <li>Type = String</li>
+ * <li>Length = 7</li>
+ * <li>Default = None</li>
+ * </ul>
+ */
public static final String TAG_OFFSET_TIME = "OffsetTime";
- /** Type is String. {@hide} */
+ /**
+ * <p>A tag used to record the offset from UTC (the time difference from Universal Time
+ * Coordinated including daylight saving time) of the time of DateTimeOriginal tag. The format
+ * when recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+ * the offsets are unknown, all the character spaces except colons (":") should be filled
+ * with blank characters, or else the Interoperability field should be filled with blank
+ * characters. The character string length is 7 Bytes including NULL for termination. When
+ * the field is left blank, it is treated as unknown.</p>
+ *
+ * <ul>
+ * <li>Tag = 36881</li>
+ * <li>Type = String</li>
+ * <li>Length = 7</li>
+ * <li>Default = None</li>
+ * </ul>
+ */
public static final String TAG_OFFSET_TIME_ORIGINAL = "OffsetTimeOriginal";
- /** Type is String. {@hide} */
+ /**
+ * <p>A tag used to record the offset from UTC (the time difference from Universal Time
+ * Coordinated including daylight saving time) of the time of DateTimeDigitized tag. The format
+ * when recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+ * the offsets are unknown, all the character spaces except colons (":") should be filled
+ * with blank characters, or else the Interoperability field should be filled with blank
+ * characters. The character string length is 7 Bytes including NULL for termination. When
+ * the field is left blank, it is treated as unknown.</p>
+ *
+ * <ul>
+ * <li>Tag = 36882</li>
+ * <li>Type = String</li>
+ * <li>Length = 7</li>
+ * <li>Default = None</li>
+ * </ul>
+ */
public static final String TAG_OFFSET_TIME_DIGITIZED = "OffsetTimeDigitized";
/** Type is int. */
public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fc056109baa4..ef451ce401e6 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -263,6 +263,8 @@ interface IAudioService {
boolean hasHapticChannels(in Uri uri);
+ boolean isCallScreeningModeSupported();
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 66764c73ee5c..d8fd1ff22c89 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -24,7 +24,7 @@ import android.media.IMediaRoute2ProviderClient;
*/
oneway interface IMediaRoute2Provider {
void setClient(IMediaRoute2ProviderClient client);
- void selectRoute(String packageName, String id);
+ void requestSelectRoute(String packageName, String id, int seq);
void unselectRoute(String packageName, String id);
void notifyControlRequestSent(String id, in Intent request);
void requestSetVolume(String id, int volume);
diff --git a/media/java/android/media/IMediaRouter2Client.aidl b/media/java/android/media/IMediaRouter2Client.aidl
index 72c33f994349..b04af7d1d28d 100644
--- a/media/java/android/media/IMediaRouter2Client.aidl
+++ b/media/java/android/media/IMediaRouter2Client.aidl
@@ -17,6 +17,7 @@
package android.media;
import android.media.MediaRoute2Info;
+import android.os.Bundle;
/**
* @hide
@@ -26,4 +27,5 @@ oneway interface IMediaRouter2Client {
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
+ void notifyRouteSelected(in MediaRoute2Info route, int reason, in Bundle controlHints);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 7b7a34e5151f..ced8615a3ee6 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -54,7 +54,7 @@ interface IMediaRouterService {
* @param client the client that changes it's selected route
* @param route the route to be selected
*/
- void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
+ void requestSelectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
void setControlCategories2(IMediaRouter2Client client, in List<String> categories);
void registerManager(IMediaRouter2Manager manager, String packageName);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 457ccb788d0d..2380077157c1 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -274,7 +274,7 @@ public final class MediaRoute2Info implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mId);
dest.writeString(mProviderId);
dest.writeString(mName);
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 8541f32ae98f..4f203dea49f5 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -95,8 +95,8 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
* Gets the route for the given route id or null if no matching route exists.
*/
@Nullable
- public MediaRoute2Info getRoute(String routeId) {
- return mRoutes.get(routeId);
+ public MediaRoute2Info getRoute(@NonNull String routeId) {
+ return mRoutes.get(Objects.requireNonNull(routeId, "routeId must not be null"));
}
/**
@@ -113,7 +113,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mUniqueId);
dest.writeTypedArrayMap(mRoutes, flags);
}
@@ -155,6 +155,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
* </p>
* @hide
*/
+ @NonNull
public Builder setUniqueId(@Nullable String uniqueId) {
if (TextUtils.equals(mUniqueId, uniqueId)) {
return this;
@@ -174,6 +175,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
/**
* Adds a route to the provider
*/
+ @NonNull
public Builder addRoute(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
@@ -192,6 +194,7 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
/**
* Adds a list of routes to the provider
*/
+ @NonNull
public Builder addRoutes(@NonNull Collection<MediaRoute2Info> routes) {
Objects.requireNonNull(routes, "routes must not be null");
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 5f5d200c6f5e..386d2dc54a88 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -128,7 +128,9 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void selectRoute(String packageName, String id) {
+ public void requestSelectRoute(String packageName, String id, int seq) {
+ // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
+ // use the sequence number here properly.
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
MediaRoute2ProviderService.this, packageName, id));
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 86fa9db32256..74d26f030529 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -103,6 +104,8 @@ public class MediaRouter2 {
private MediaRoute2Info mSelectedRoute;
@GuardedBy("sLock")
+ private MediaRoute2Info mSelectingRoute;
+ @GuardedBy("sLock")
private Client mClient;
final Handler mHandler;
@@ -250,24 +253,28 @@ public class MediaRouter2 {
}
/**
- * Selects the specified route.
+ * Request to select the specified route. When the route is selected,
+ * {@link Callback#onRouteSelected(MediaRoute2Info, int, Bundle)} will be called.
*
* @param route the route to select
*/
- //TODO: add a parameter for category (e.g. mirroring/casting)
- public void selectRoute(@NonNull MediaRoute2Info route) {
+ public void requestSelectRoute(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
Client client;
synchronized (sLock) {
- mSelectedRoute = route;
+ if (mSelectingRoute == route) {
+ Log.w(TAG, "The route selection request is already sent.");
+ return;
+ }
+ mSelectingRoute = route;
client = mClient;
}
if (client != null) {
try {
- mMediaRouterService.selectRoute2(client, route);
+ mMediaRouterService.requestSelectRoute2(client, route);
} catch (RemoteException ex) {
- Log.e(TAG, "Unable to select route.", ex);
+ Log.e(TAG, "Unable to request to select route.", ex);
}
}
}
@@ -443,6 +450,22 @@ public class MediaRouter2 {
}
}
+ void selectRouteOnHandler(MediaRoute2Info route, int reason, Bundle controlHints) {
+ synchronized (sLock) {
+ if (reason == SELECT_REASON_USER_SELECTED) {
+ if (mSelectingRoute == null
+ || !TextUtils.equals(mSelectingRoute.getUniqueId(), route.getUniqueId())) {
+ Log.w(TAG, "Ignoring invalid or outdated notifyRouteSelected call. "
+ + "selectingRoute=" + mSelectingRoute + " route=" + route);
+ return;
+ }
+ }
+ mSelectingRoute = null;
+ }
+ mSelectedRoute = route;
+ notifyRouteSelected(route, reason, controlHints);
+ }
+
private void refreshFilteredRoutes() {
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
@@ -475,12 +498,17 @@ public class MediaRouter2 {
}
}
+ private void notifyRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+ for (CallbackRecord record: mCallbackRecords) {
+ record.mExecutor.execute(
+ () -> record.mCallback.onRouteSelected(route, reason, controlHints));
+ }
+ }
+
/**
* Interface for receiving events about media routing changes.
*/
public static class Callback {
- //TODO: clean up these callbacks
-
/**
* Called when routes are added.
* @param routes the list of routes that have been added. It's never empty.
@@ -505,20 +533,19 @@ public class MediaRouter2 {
*/
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
- // TODO: Make this callback be called when we add requestSelectRoute().
/**
* Called when a route is selected. Exactly one route can be selected at a time.
* @param route the selected route.
* @param reason the reason why the route is selected.
- * @param connectionHints An optional bundle of provider-specific arguments which may be
- * used to control the selected route. Can be empty.
+ * @param controlHints An optional bundle of provider-specific arguments which may be
+ * used to control the selected route. Can be empty.
* @see #SELECT_REASON_UNKNOWN
* @see #SELECT_REASON_USER_SELECTED
* @see #SELECT_REASON_FALLBACK
* @see #getSelectedRoute()
*/
public void onRouteSelected(@NonNull MediaRoute2Info route, @SelectReason int reason,
- @NonNull Bundle connectionHints) {}
+ @NonNull Bundle controlHints) {}
}
final class CallbackRecord {
@@ -560,5 +587,12 @@ public class MediaRouter2 {
mHandler.sendMessage(obtainMessage(MediaRouter2::changeRoutesOnHandler,
MediaRouter2.this, routes));
}
+
+ @Override
+ public void notifyRouteSelected(MediaRoute2Info route, int reason,
+ Bundle controlHints) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2::selectRouteOnHandler,
+ MediaRouter2.this, route, reason, controlHints));
+ }
}
}
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 7eec8d9f6cc3..8d857243bc05 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -197,7 +197,7 @@ public class MediaScannerConnection implements ServiceConnection {
private static Uri scanFileQuietly(ContentProviderClient client, File file) {
Uri uri = null;
try {
- uri = MediaStore.scanFile(client, file);
+ uri = MediaStore.scanFile(client, file.getCanonicalFile());
Log.d(TAG, "Scanned " + file + " to " + uri);
} catch (Exception e) {
Log.w(TAG, "Failed to scan " + file + ": " + e);
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d68d0279f1f..8805b7be9afd 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -35,6 +35,7 @@ public final class Tuner implements AutoCloseable {
private static final int MSG_ON_FRONTEND_EVENT = 1;
private static final int MSG_ON_FILTER_EVENT = 2;
private static final int MSG_ON_FILTER_STATUS = 3;
+ private static final int MSG_ON_LNB_EVENT = 4;
static {
System.loadLibrary("media_tv_tuner");
@@ -45,6 +46,9 @@ public final class Tuner implements AutoCloseable {
private Frontend mFrontend;
private EventHandler mHandler;
+ private List<Integer> mLnbIds;
+ private Lnb mLnb;
+
public Tuner() {
nativeSetup();
}
@@ -76,6 +80,8 @@ public final class Tuner implements AutoCloseable {
private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+ private native List<Integer> nativeGetLnbIds();
+ private native Lnb nativeOpenLnbById(int id);
/**
* Frontend Callback.
@@ -89,6 +95,16 @@ public final class Tuner implements AutoCloseable {
}
/**
+ * LNB Callback.
+ */
+ public interface LnbCallback {
+ /**
+ * Invoked when there is a LNB event.
+ */
+ void onEvent(int lnbEventType);
+ }
+
+ /**
* Frontend Callback.
*/
public interface FilterCallback {
@@ -129,6 +145,11 @@ public final class Tuner implements AutoCloseable {
}
break;
}
+ case MSG_ON_LNB_EVENT: {
+ if (mLnb != null && mLnb.mCallback != null) {
+ mLnb.mCallback.onEvent(msg.arg1);
+ }
+ }
default:
// fall through
}
@@ -193,6 +214,11 @@ public final class Tuner implements AutoCloseable {
private long mNativeContext;
private FilterCallback mCallback;
int mId;
+
+ private native boolean nativeStartFilter();
+ private native boolean nativeStopFilter();
+ private native boolean nativeFlushFilter();
+
private Filter(int id) {
mId = id;
}
@@ -203,6 +229,18 @@ public final class Tuner implements AutoCloseable {
mHandler.obtainMessage(MSG_ON_FILTER_STATUS, status, 0, this));
}
}
+
+ public boolean start() {
+ return nativeStartFilter();
+ }
+
+ public boolean stop() {
+ return nativeStopFilter();
+ }
+
+ public boolean flush() {
+ return nativeFlushFilter();
+ }
}
private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) {
@@ -215,4 +253,45 @@ public final class Tuner implements AutoCloseable {
}
return filter;
}
+
+ protected class Lnb {
+ private int mId;
+ private LnbCallback mCallback;
+
+ private Lnb(int id) {
+ mId = id;
+ }
+
+ public void setCallback(@Nullable LnbCallback callback) {
+ mCallback = callback;
+ if (mCallback == null) {
+ return;
+ }
+ if (mHandler == null) {
+ mHandler = createEventHandler();
+ }
+ }
+ }
+
+ private List<Integer> getLnbIds() {
+ mLnbIds = nativeGetLnbIds();
+ return mLnbIds;
+ }
+
+ private Lnb openLnbById(int id) {
+ if (mLnbIds == null) {
+ mLnbIds = getLnbIds();
+ }
+ if (!mLnbIds.contains(id)) {
+ return null;
+ }
+ mLnb = nativeOpenLnbById(id);
+ return mLnb;
+ }
+
+ private void onLnbEvent(int eventType) {
+ if (mHandler != null) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LNB_EVENT, eventType, 0));
+ }
+ }
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 99394adec27d..3833c6bfb676 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -211,48 +211,6 @@ static fields_t gFields;
namespace {
-// Helper function to convert a native PersistableBundle to a Java
-// PersistableBundle.
-jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
- PersistableBundle* nativeBundle) {
- if (env == NULL || thiz == NULL || nativeBundle == NULL) {
- ALOGE("Unexpected NULL parmeter");
- return NULL;
- }
-
- // Create a Java parcel with the native parcel data.
- // Then create a new PersistableBundle with that parcel as a parameter.
- jobject jParcel = android::createJavaParcelObject(env);
- if (jParcel == NULL) {
- ALOGE("Failed to create a Java Parcel.");
- return NULL;
- }
-
- android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
- if (nativeParcel == NULL) {
- ALOGE("Failed to get the native Parcel.");
- return NULL;
- }
-
- android::status_t result = nativeBundle->writeToParcel(nativeParcel);
- nativeParcel->setDataPosition(0);
- if (result != android::OK) {
- ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
- return NULL;
- }
-
- jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
- gFields.createFromParcelId,
- jParcel);
- if (newBundle == NULL) {
- ALOGE("Failed to create a new PersistableBundle "
- "from the createFromParcel call.");
- }
-
- return newBundle;
-}
-
-
jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
size_t length = vector.size();
@@ -1937,7 +1895,7 @@ android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
return (jobject) NULL;
}
- return nativeToJavaPersistableBundle(env, thiz, &metrics);
+ return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
}
static jbyteArray android_media_MediaDrm_signRSANative(
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index e7487c3cbc67..5ddfcfce072e 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -20,7 +20,9 @@
#include <nativehelper/JNIHelp.h>
#include "android_media_MediaMetricsJNI.h"
+#include "android_os_Parcel.h"
#include <media/MediaAnalyticsItem.h>
+#include <binder/Parcel.h>
// This source file is compiled and linked into:
@@ -223,5 +225,72 @@ jobject MediaMetricsJNI::writeAttributesToBundle(JNIEnv* env, jobject mybundle,
return NULL;
}
+// Helper function to convert a native PersistableBundle to a Java
+// PersistableBundle.
+jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env,
+ os::PersistableBundle* nativeBundle) {
+ if (env == NULL || nativeBundle == NULL) {
+ ALOGE("Unexpected NULL parmeter");
+ return NULL;
+ }
+
+ // Create a Java parcel with the native parcel data.
+ // Then create a new PersistableBundle with that parcel as a parameter.
+ jobject jParcel = android::createJavaParcelObject(env);
+ if (jParcel == NULL) {
+ ALOGE("Failed to create a Java Parcel.");
+ return NULL;
+ }
+
+ android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
+ if (nativeParcel == NULL) {
+ ALOGE("Failed to get the native Parcel.");
+ return NULL;
+ }
+
+ android::status_t result = nativeBundle->writeToParcel(nativeParcel);
+ nativeParcel->setDataPosition(0);
+ if (result != android::OK) {
+ ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
+ return NULL;
+ }
+
+#define STATIC_INIT_JNI(T, obj, method, globalref, ...) \
+ static T obj{};\
+ if (obj == NULL) { \
+ obj = method(__VA_ARGS__); \
+ if (obj == NULL) { \
+ ALOGE("%s can't find " #obj, __func__); \
+ return NULL; \
+ } else { \
+ obj = globalref; \
+ }\
+ } \
+
+ STATIC_INIT_JNI(jclass, clazzBundle, env->FindClass,
+ static_cast<jclass>(env->NewGlobalRef(clazzBundle)),
+ "android/os/PersistableBundle");
+ STATIC_INIT_JNI(jfieldID, bundleCreatorId, env->GetStaticFieldID,
+ bundleCreatorId,
+ clazzBundle, "CREATOR", "Landroid/os/Parcelable$Creator;");
+ STATIC_INIT_JNI(jobject, bundleCreator, env->GetStaticObjectField,
+ env->NewGlobalRef(bundleCreator),
+ clazzBundle, bundleCreatorId);
+ STATIC_INIT_JNI(jclass, clazzCreator, env->FindClass,
+ static_cast<jclass>(env->NewGlobalRef(clazzCreator)),
+ "android/os/Parcelable$Creator");
+ STATIC_INIT_JNI(jmethodID, createFromParcelId, env->GetMethodID,
+ createFromParcelId,
+ clazzCreator, "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;");
+
+ jobject newBundle = env->CallObjectMethod(bundleCreator, createFromParcelId, jParcel);
+ if (newBundle == NULL) {
+ ALOGE("Failed to create a new PersistableBundle "
+ "from the createFromParcel call.");
+ }
+
+ return newBundle;
+}
+
}; // namespace android
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
index a10780f5c5c3..e879da01c6ef 100644
--- a/media/jni/android_media_MediaMetricsJNI.h
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -20,6 +20,7 @@
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <media/MediaAnalyticsItem.h>
+#include <binder/PersistableBundle.h>
// Copeid from core/jni/ (libandroid_runtime.so)
namespace android {
@@ -28,6 +29,7 @@ class MediaMetricsJNI {
public:
static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle);
static jobject writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length);
+ static jobject nativeToJavaPersistableBundle(JNIEnv*, os::PersistableBundle*);
};
}; // namespace android
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 26405720c31f..35607ac6d5e9 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -39,11 +39,30 @@ struct fields_t {
jmethodID filterInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
+ jmethodID lnbInitID;
+ jmethodID onLnbEventID;
};
static fields_t gFields;
namespace android {
+/////////////// LnbCallback ///////////////////////
+LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {}
+
+Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
+ ALOGD("LnbCallback::onEvent, type=%d", lnbEventType);
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(
+ mObject,
+ gFields.onLnbEventID,
+ (jint)lnbEventType);
+ return Void();
+}
+Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
+ ALOGD("LnbCallback::onDiseqcMessage");
+ return Void();
+}
+
/////////////// FilterCallback ///////////////////////
//TODO: implement filter callback
Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
@@ -175,6 +194,52 @@ jobject JTuner::openFrontendById(int id) {
(jint) jId);
}
+jobject JTuner::getLnbIds() {
+ ALOGD("JTuner::getLnbIds()");
+ mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
+ mLnbIds = lnbIds;
+ });
+ if (mLnbIds.size() == 0) {
+ ALOGW("Lnb isn't available");
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass arrayListClazz = env->FindClass("java/util/ArrayList");
+ jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
+ jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
+
+ jclass integerClazz = env->FindClass("java/lang/Integer");
+ jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
+
+ for (int i=0; i < mLnbIds.size(); i++) {
+ jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]);
+ env->CallBooleanMethod(obj, arrayListAdd, idObj);
+ }
+ return obj;
+}
+
+jobject JTuner::openLnbById(int id) {
+ sp<ILnb> lnbSp;
+ mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) {
+ lnbSp = lnb;
+ });
+ if (lnbSp == nullptr) {
+ ALOGE("Failed to open lnb");
+ return NULL;
+ }
+ mLnb = lnbSp;
+ sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+ mLnb->setCallback(lnbCb);
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ return env->NewObject(
+ env->FindClass("android/media/tv/tuner/Tuner$Lnb"),
+ gFields.lnbInitID,
+ mObject,
+ id);
+}
+
bool JTuner::openDemux() {
if (mTuner == nullptr) {
return false;
@@ -268,10 +333,16 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) {
gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
+ gFields.onLnbEventID = env->GetMethodID(clazz, "onLnbEvent", "(I)V");
+
jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
gFields.frontendInitID =
env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
+ jclass lnbClazz = env->FindClass("android/media/tv/tuner/Tuner$Lnb");
+ gFields.lnbInitID =
+ env->GetMethodID(lnbClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
+
jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
gFields.filterInitID =
@@ -295,6 +366,16 @@ static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject t
return tuner->openFrontendById(id);
}
+static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->getLnbIds();
+}
+
+static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openLnbById(id);
+}
+
static jobject android_media_tv_Tuner_open_filter(
JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) {
sp<JTuner> tuner = getTuner(env, thiz);
@@ -308,7 +389,34 @@ static jobject android_media_tv_Tuner_open_filter(
return tuner->openFilter(filterType, bufferSize);
}
-static const JNINativeMethod gMethods[] = {
+static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
+ sp<IFilter> filterSp = getFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed to start filter: filter not found");
+ return false;
+ }
+ return filterSp->start() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
+ sp<IFilter> filterSp = getFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed to stop filter: filter not found");
+ return false;
+ }
+ return filterSp->stop() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
+ sp<IFilter> filterSp = getFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed to flush filter: filter not found");
+ return false;
+ }
+ return filterSp->flush() == Result::SUCCESS;
+}
+
+static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
{ "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
{ "nativeGetFrontendIds", "()Ljava/util/List;",
@@ -317,11 +425,32 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_tv_Tuner_open_frontend_by_id },
{ "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
(void *)android_media_tv_Tuner_open_filter },
+ { "nativeGetLnbIds", "()Ljava/util/List;",
+ (void *)android_media_tv_Tuner_get_lnb_ids },
+ { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
+ (void *)android_media_tv_Tuner_open_lnb_by_id },
+};
+
+static const JNINativeMethod gFilterMethods[] = {
+ { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter },
+ { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter },
+ { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter },
};
-static int register_android_media_tv_Tuner(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(
- env, "android/media/tv/tuner/Tuner", gMethods, NELEM(gMethods));
+static bool register_android_media_tv_Tuner(JNIEnv *env) {
+ if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) {
+ ALOGE("Failed to register tuner native methods");
+ return false;
+ }
+ if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/Tuner$Filter",
+ gFilterMethods,
+ NELEM(gFilterMethods)) != JNI_OK) {
+ ALOGE("Failed to register filter native methods");
+ return false;
+ }
+ return true;
}
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
@@ -335,7 +464,7 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
}
assert(env != NULL);
- if (register_android_media_tv_Tuner(env) != JNI_OK) {
+ if (!register_android_media_tv_Tuner(env)) {
ALOGE("ERROR: Tuner native registration failed\n");
return result;
}
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index ab48761f36be..f42f032cacc2 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -37,10 +37,22 @@ using ::android::hardware::tv::tuner::V1_0::IFilter;
using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
using ::android::hardware::tv::tuner::V1_0::IFrontend;
using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using ::android::hardware::tv::tuner::V1_0::ILnb;
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::LnbEventType;
+using ::android::hardware::tv::tuner::V1_0::LnbId;
namespace android {
+struct LnbCallback : public ILnbCallback {
+ LnbCallback(jweak tunerObj, LnbId id);
+ virtual Return<void> onEvent(LnbEventType lnbEventType);
+ virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+ jweak mObject;
+ LnbId mId;
+};
+
struct FilterCallback : public IFilterCallback {
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
@@ -67,7 +79,10 @@ struct JTuner : public RefBase {
sp<ITuner> getTunerService();
jobject getFrontendIds();
jobject openFrontendById(int id);
+ jobject getLnbIds();
+ jobject openLnbById(int id);
jobject openFilter(DemuxFilterType type, int bufferSize);
+
protected:
bool openDemux();
virtual ~JTuner();
@@ -78,6 +93,8 @@ private:
static sp<ITuner> mTuner;
hidl_vec<FrontendId> mFeIds;
sp<IFrontend> mFe;
+ hidl_vec<LnbId> mLnbIds;
+ sp<ILnb> mLnb;
sp<IDemux> mDemux;
int mDemuxId;
};
diff --git a/media/lib/tvremote/OWNERS b/media/lib/tvremote/OWNERS
new file mode 100644
index 000000000000..81d52e1d72db
--- /dev/null
+++ b/media/lib/tvremote/OWNERS
@@ -0,0 +1,2 @@
+nutka@google.com
+skill@google.com
diff --git a/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
index 35322ad8ee6b..0bf0f97d2c5e 100644
--- a/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
+++ b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
@@ -19,18 +19,18 @@ package com.android.media.tv.remoteprovider;
import android.content.Context;
import android.media.tv.ITvRemoteProvider;
import android.media.tv.ITvRemoteServiceInput;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import java.util.LinkedList;
+
/**
* Base class for emote providers implemented in unbundled service.
* <p/>
* This object is not thread safe. It is only intended to be accessed on the
* {@link Context#getMainLooper main looper thread} of an application.
+ * The callback {@link #onInputBridgeConnected()} may be called from a different thread.
* </p><p>
* IMPORTANT: This class is effectively a system API for unbundled emote service, and
* must remain API stable. See README.txt in the root of this package for more information.
@@ -50,11 +50,9 @@ public abstract class TvRemoteProvider {
private static final String TAG = "TvRemoteProvider";
private static final boolean DEBUG_KEYS = false;
- private static final int MSG_SET_SERVICE_INPUT = 1;
- private static final int MSG_SEND_INPUTBRIDGE_CONNECTED = 2;
private final Context mContext;
private final ProviderStub mStub;
- private final ProviderHandler mHandler;
+ private final LinkedList<Runnable> mOpenBridgeRunnables;
private ITvRemoteServiceInput mRemoteServiceInput;
/**
@@ -67,7 +65,7 @@ public abstract class TvRemoteProvider {
public TvRemoteProvider(Context context) {
mContext = context.getApplicationContext();
mStub = new ProviderStub();
- mHandler = new ProviderHandler(mContext.getMainLooper());
+ mOpenBridgeRunnables = new LinkedList<Runnable>();
}
/**
@@ -77,7 +75,6 @@ public abstract class TvRemoteProvider {
return mContext;
}
-
/**
* Gets the Binder associated with the provider.
* <p>
@@ -105,7 +102,11 @@ public abstract class TvRemoteProvider {
* @param tvServiceInput sink defined in framework service
*/
private void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
- mRemoteServiceInput = tvServiceInput;
+ synchronized (mOpenBridgeRunnables) {
+ mRemoteServiceInput = tvServiceInput;
+ }
+ mOpenBridgeRunnables.forEach(Runnable::run);
+ mOpenBridgeRunnables.clear();
}
/**
@@ -125,8 +126,25 @@ public abstract class TvRemoteProvider {
*/
public void openRemoteInputBridge(IBinder token, String name, int width, int height,
int maxPointers) throws RuntimeException {
+ synchronized (mOpenBridgeRunnables) {
+ if (mRemoteServiceInput == null) {
+ Log.d(TAG, "Delaying openRemoteInputBridge() for " + name);
+
+ mOpenBridgeRunnables.add(() -> {
+ try {
+ mRemoteServiceInput.openInputBridge(
+ token, name, width, height, maxPointers);
+ Log.d(TAG, "Delayed openRemoteInputBridge() for " + name + ": success");
+ } catch (RemoteException re) {
+ Log.e(TAG, "Delayed openRemoteInputBridge() for " + name + ": failure", re);
+ }
+ });
+ return;
+ }
+ }
try {
mRemoteServiceInput.openInputBridge(token, name, width, height, maxPointers);
+ Log.d(TAG, "openRemoteInputBridge() for " + name + ": success");
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -271,33 +289,12 @@ public abstract class TvRemoteProvider {
private final class ProviderStub extends ITvRemoteProvider.Stub {
@Override
public void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
- mHandler.obtainMessage(MSG_SET_SERVICE_INPUT, tvServiceInput).sendToTarget();
+ TvRemoteProvider.this.setRemoteServiceInputSink(tvServiceInput);
}
@Override
public void onInputBridgeConnected(IBinder token) {
- mHandler.obtainMessage(MSG_SEND_INPUTBRIDGE_CONNECTED, 0, 0,
- (IBinder) token).sendToTarget();
- }
- }
-
- private final class ProviderHandler extends Handler {
- public ProviderHandler(Looper looper) {
- super(looper, null, true);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SET_SERVICE_INPUT: {
- setRemoteServiceInputSink((ITvRemoteServiceInput) msg.obj);
- break;
- }
- case MSG_SEND_INPUTBRIDGE_CONNECTED: {
- onInputBridgeConnected((IBinder) msg.obj);
- break;
- }
- }
+ TvRemoteProvider.this.onInputBridgeConnected(token);
}
}
}
diff --git a/media/lib/tvremote/tests/Android.bp b/media/lib/tvremote/tests/Android.bp
new file mode 100644
index 000000000000..f00eed070798
--- /dev/null
+++ b/media/lib/tvremote/tests/Android.bp
@@ -0,0 +1,15 @@
+android_test {
+ name: "TvRemoteTests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "com.android.media.tv.remoteprovider",
+ ],
+ static_libs: [
+ "mockito-target-minus-junit4",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+}
diff --git a/tests/WindowManagerStressTest/res/values/colors.xml b/media/lib/tvremote/tests/AndroidManifest.xml
index 4270ca68a860..4f843f701d20 100644
--- a/tests/WindowManagerStressTest/res/values/colors.xml
+++ b/media/lib/tvremote/tests/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,8 +13,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
-</resources>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.tv.remoteprovider">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.media.tv.remoteprovider"
+ android:label="Tests for TV Remote"/>
+</manifest>
diff --git a/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
new file mode 100644
index 000000000000..c9ce56138217
--- /dev/null
+++ b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.tv.remoteprovider;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.Context;
+import android.media.tv.ITvRemoteProvider;
+import android.media.tv.ITvRemoteServiceInput;
+import android.os.Binder;
+import android.os.IBinder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+
+public class TvRemoteProviderTest extends AndroidTestCase {
+ private static final String TAG = TvRemoteProviderTest.class.getSimpleName();
+
+ @SmallTest
+ public void testOpenRemoteInputBridge() throws Exception {
+ Binder tokenA = new Binder();
+ Binder tokenB = new Binder();
+ Binder tokenC = new Binder();
+
+ class LocalTvRemoteProvider extends TvRemoteProvider {
+ private final ArrayList<IBinder> mTokens = new ArrayList<IBinder>();
+
+ LocalTvRemoteProvider(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onInputBridgeConnected(IBinder token) {
+ mTokens.add(token);
+ }
+
+ public boolean verifyTokens() {
+ return mTokens.size() == 3
+ && mTokens.contains(tokenA)
+ && mTokens.contains(tokenB)
+ && mTokens.contains(tokenC);
+ }
+ }
+
+ LocalTvRemoteProvider tvProvider = new LocalTvRemoteProvider(getContext());
+ ITvRemoteProvider binder = (ITvRemoteProvider) tvProvider.getBinder();
+
+ ITvRemoteServiceInput tvServiceInput = mock(ITvRemoteServiceInput.class);
+ doAnswer((i) -> {
+ binder.onInputBridgeConnected(i.getArgument(0));
+ return null;
+ }).when(tvServiceInput).openInputBridge(any(), any(), anyInt(), anyInt(), anyInt());
+
+ tvProvider.openRemoteInputBridge(tokenA, "A", 1, 1, 1);
+ tvProvider.openRemoteInputBridge(tokenB, "B", 1, 1, 1);
+ binder.setRemoteServiceInputSink(tvServiceInput);
+ tvProvider.openRemoteInputBridge(tokenC, "C", 1, 1, 1);
+
+ verify(tvServiceInput).openInputBridge(tokenA, "A", 1, 1, 1);
+ verify(tvServiceInput).openInputBridge(tokenB, "B", 1, 1, 1);
+ verify(tvServiceInput).openInputBridge(tokenC, "C", 1, 1, 1);
+ verifyNoMoreInteractions(tvServiceInput);
+
+ assertTrue(tvProvider.verifyTokens());
+ }
+}
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index ce022a8b0f19..cb04d921bd67 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -73,6 +73,7 @@
?audio/3gpp 3gpp 3ga
?audio/aac-adts aac
?audio/ac3 ac3 a52
+?audio/amr amr
?audio/imelody imy
?audio/midi rtttl xmf
?audio/mobile-xmf mxmf
diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt
index be3531da462d..8d4e9009cc56 100644
--- a/native/android/libandroid_net.map.txt
+++ b/native/android/libandroid_net.map.txt
@@ -1,15 +1,19 @@
-# They are also all available to vendor code.
+# The following symbols marked with # llndk are available to vendor code.
+# Unlike other VNDK libraries where keeping backwards compatibility is required
+# only within a platform release, these symbols need much longer suppport
+# because the same LLNDK library serves for both system and vendor partition
+# which might be a few years old.
LIBANDROID_NET {
global:
# These functions have been part of the NDK since API 24.
- android_getaddrinfofornetwork; # vndk
- android_setsocknetwork; # vndk
- android_setprocnetwork; # vndk
+ android_getaddrinfofornetwork; # llndk
+ android_setsocknetwork; # llndk
+ android_setprocnetwork; # llndk
# These functions have been part of the NDK since API 29.
- android_res_cancel; # vndk
- android_res_nquery; # vndk
- android_res_nresult; # vndk
- android_res_nsend; # vndk
+ android_res_cancel; # llndk
+ android_res_nquery; # llndk
+ android_res_nresult; # llndk
+ android_res_nsend; # llndk
local:
*;
};
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index c35303e1e6c9..2bd5fe228f41 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -19,36 +19,16 @@ package com.android.systemui;
import android.content.Context;
import com.android.systemui.dagger.SystemUIRootComponent;
-import com.android.systemui.navigationbar.car.CarFacetButtonController;
-
-import javax.inject.Singleton;
-
-import dagger.Component;
/**
* Class factory to provide car specific SystemUI components.
*/
public class CarSystemUIFactory extends SystemUIFactory {
- private CarDependencyComponent mCarDependencyComponent;
-
@Override
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
- mCarDependencyComponent = DaggerCarSystemUIFactory_CarDependencyComponent.builder()
- .contextHolder(new ContextHolder(context))
- .build();
return DaggerCarSystemUIRootComponent.builder()
.contextHolder(new ContextHolder(context))
.build();
}
-
- public CarDependencyComponent getCarDependencyComponent() {
- return mCarDependencyComponent;
- }
-
- @Singleton
- @Component(modules = ContextHolder.class)
- public interface CarDependencyComponent {
- CarFacetButtonController getCarFacetButtonController();
- }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 91d00262dc18..818fdeaef8db 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -38,7 +38,6 @@ import com.android.systemui.statusbar.car.CarStatusBar;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -101,7 +100,7 @@ abstract class CarSystemUIModule {
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment(
+ abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
KeyguardEnvironmentImpl keyguardEnvironment);
@Binds
diff --git a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
new file mode 100644
index 000000000000..f90947cbeb15
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "auto-postsubmit": [
+ {
+ "name": "AndroidAutoUiTests",
+ "options" : [
+ {
+ "include-filter": "android.test.functional.auto.apps.HomeHelperTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 53a88a9a54e9..ed945e7d4e72 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -19,8 +19,9 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -35,8 +36,12 @@ import javax.inject.Singleton;
public class CarNotificationEntryManager extends NotificationEntryManager {
@Inject
- public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
- super(notificationData, notifLog);
+ public CarNotificationEntryManager(
+ NotifLog notifLog,
+ NotificationGroupManager groupManager,
+ NotificationRankingManager rankingManager,
+ KeyguardEnvironment keyguardEnvironment) {
+ super(notifLog, groupManager, rankingManager, keyguardEnvironment);
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
new file mode 100644
index 000000000000..80ee37127965
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
@@ -0,0 +1,79 @@
+/*
+ * 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.car;
+
+import android.car.Car;
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Provides a common connection to the car service that can be shared. */
+@Singleton
+public class CarServiceProvider {
+
+ private final Context mContext;
+ private final List<CarServiceOnConnectedListener> mListeners = new ArrayList<>();
+ private Car mCar;
+
+ @Inject
+ public CarServiceProvider(Context context) {
+ mContext = context;
+ mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+ (car, ready) -> {
+ mCar = car;
+
+ synchronized (mListeners) {
+ for (CarServiceOnConnectedListener listener : mListeners) {
+ if (ready) {
+ listener.onConnected(mCar);
+ }
+ }
+ }
+ });
+ }
+
+ @VisibleForTesting
+ public CarServiceProvider(Context context, Car car) {
+ mContext = context;
+ mCar = car;
+ }
+
+ /**
+ * Let's other components hook into the connection to the car service. If we're already
+ * connected to the car service, the callback is immediately triggered.
+ */
+ public void addListener(CarServiceOnConnectedListener listener) {
+ if (mCar.isConnected()) {
+ listener.onConnected(mCar);
+ }
+ mListeners.add(listener);
+ }
+
+ /**
+ * Listener which is triggered when Car Service is connected.
+ */
+ public interface CarServiceOnConnectedListener {
+ /** This will be called when the car service has successfully been connected. */
+ void onConnected(Car car);
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
index c46e6e7433a3..0b8999263c73 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
@@ -29,9 +29,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.keyguard.AlphaOptimizedImageButton;
-import com.android.systemui.CarSystemUIFactory;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
/**
* CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined
@@ -82,10 +80,6 @@ public class CarFacetButton extends LinearLayout {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
setupIntents(typedArray);
setupIcons(typedArray);
- CarSystemUIFactory factory = SystemUIFactory.getInstance();
- CarFacetButtonController carFacetButtonController = factory.getCarDependencyComponent()
- .getCarFacetButtonController();
- carFacetButtonController.addFacetButton(this);
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
index 30f63f052b9f..f66e8280197e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
@@ -43,6 +43,8 @@ import javax.inject.Singleton;
@Singleton
public class CarFacetButtonController {
+ private final Set<CarFacetButton> mRegisteredViews = new HashSet<>();
+
protected ButtonMap mButtonsByCategory = new ButtonMap();
protected ButtonMap mButtonsByPackage = new ButtonMap();
protected ButtonMap mButtonsByComponentName = new ButtonMap();
@@ -60,7 +62,11 @@ public class CarFacetButtonController {
* to get a reference to this controller via {@link com.android.systemui.Dependency}
* and self add.
*/
- public void addFacetButton(CarFacetButton facetButton) {
+ private void addFacetButton(CarFacetButton facetButton) {
+ if (mRegisteredViews.contains(facetButton)) {
+ return;
+ }
+
String[] categories = facetButton.getCategories();
for (int i = 0; i < categories.length; i++) {
mButtonsByCategory.add(categories[i], facetButton);
@@ -74,6 +80,8 @@ public class CarFacetButtonController {
for (int i = 0; i < componentNames.length; i++) {
mButtonsByComponentName.add(componentNames[i], facetButton);
}
+
+ mRegisteredViews.add(facetButton);
}
/** Removes all buttons from the button maps. */
@@ -82,6 +90,7 @@ public class CarFacetButtonController {
mButtonsByPackage.clear();
mButtonsByComponentName.clear();
mSelectedFacetButtons.clear();
+ mRegisteredViews.clear();
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index af92767efc49..08ab4928adfe 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -37,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -54,10 +55,12 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
private final WindowManager mWindowManager;
private final DeviceProvisionedController mDeviceProvisionedController;
private final CommandQueue mCommandQueue;
- private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener;
+ private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListenerLazy;
private final Handler mMainHandler;
- private final Lazy<KeyguardStateController> mKeyguardStateController;
- private final Lazy<NavigationBarController> mNavigationBarController;
+ private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
+ private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
+ private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+ private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy;
private IStatusBarService mBarService;
private ActivityManagerWrapper mActivityManagerWrapper;
@@ -67,10 +70,12 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
private boolean mBottomNavBarVisible;
// Nav bar views.
- private ViewGroup mNavigationBarWindow;
+ private ViewGroup mTopNavigationBarWindow;
+ private ViewGroup mBottomNavigationBarWindow;
private ViewGroup mLeftNavigationBarWindow;
private ViewGroup mRightNavigationBarWindow;
- private CarNavigationBarView mNavigationBarView;
+ private CarNavigationBarView mTopNavigationBarView;
+ private CarNavigationBarView mBottomNavigationBarView;
private CarNavigationBarView mLeftNavigationBarView;
private CarNavigationBarView mRightNavigationBarView;
@@ -84,19 +89,23 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager windowManager,
DeviceProvisionedController deviceProvisionedController,
CommandQueue commandQueue,
- Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener,
+ Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListenerLazy,
@MainHandler Handler mainHandler,
- Lazy<KeyguardStateController> keyguardStateController,
- Lazy<NavigationBarController> navigationBarController) {
+ Lazy<KeyguardStateController> keyguardStateControllerLazy,
+ Lazy<NavigationBarController> navigationBarControllerLazy,
+ SuperStatusBarViewFactory superStatusBarViewFactory,
+ Lazy<CarFacetButtonController> carFacetButtonControllerLazy) {
super(context);
mCarNavigationBarController = carNavigationBarController;
mWindowManager = windowManager;
mDeviceProvisionedController = deviceProvisionedController;
mCommandQueue = commandQueue;
- mFacetButtonTaskStackListener = facetButtonTaskStackListener;
+ mFacetButtonTaskStackListenerLazy = facetButtonTaskStackListenerLazy;
mMainHandler = mainHandler;
- mKeyguardStateController = keyguardStateController;
- mNavigationBarController = navigationBarController;
+ mKeyguardStateControllerLazy = keyguardStateControllerLazy;
+ mNavigationBarControllerLazy = navigationBarControllerLazy;
+ mSuperStatusBarViewFactory = superStatusBarViewFactory;
+ mCarFacetButtonControllerLazy = carFacetButtonControllerLazy;
}
@Override
@@ -137,7 +146,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
createNavigationBar(result);
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
- mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get());
+ mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListenerLazy.get());
mCarNavigationBarController.connectToHvac();
}
@@ -158,10 +167,16 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
// remove and reattach all hvac components such that we don't keep a reference to unused
// ui elements
mCarNavigationBarController.removeAllFromHvac();
+ mCarFacetButtonControllerLazy.get().removeAll();
- if (mNavigationBarWindow != null) {
- mNavigationBarWindow.removeAllViews();
- mNavigationBarView = null;
+ if (mTopNavigationBarWindow != null) {
+ mTopNavigationBarWindow.removeAllViews();
+ mTopNavigationBarView = null;
+ }
+
+ if (mBottomNavigationBarWindow != null) {
+ mBottomNavigationBarWindow.removeAllViews();
+ mBottomNavigationBarView = null;
}
if (mLeftNavigationBarWindow != null) {
@@ -177,8 +192,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
buildNavBarContent();
// If the UI was rebuilt (day/night change) while the keyguard was up we need to
// correctly respect that state.
- if (mKeyguardStateController.get().isShowing()) {
- updateNavBarForKeyguardContent();
+ if (mKeyguardStateControllerLazy.get().isShowing()) {
+ mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
}
}
@@ -196,20 +211,28 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
// There has been a car customized nav bar on the default display, so just create nav bars
// on external displays.
- mNavigationBarController.get().createNavigationBars(/* includeDefaultDisplay= */ false,
+ mNavigationBarControllerLazy.get().createNavigationBars(/* includeDefaultDisplay= */ false,
result);
}
private void buildNavBarWindows() {
- mNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
+ mTopNavigationBarWindow = mSuperStatusBarViewFactory
+ .getStatusBarWindowView()
+ .findViewById(R.id.car_top_navigation_bar_container);
+ mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
}
private void buildNavBarContent() {
- mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
- if (mNavigationBarView != null) {
- mNavigationBarWindow.addView(mNavigationBarView);
+ mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
+ if (mTopNavigationBarView != null) {
+ mTopNavigationBarWindow.addView(mTopNavigationBarView);
+ }
+
+ mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
+ if (mBottomNavigationBarView != null) {
+ mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
}
mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser);
@@ -224,7 +247,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
}
private void attachNavBarWindows() {
- if (mNavigationBarWindow != null && !mBottomNavBarVisible) {
+ if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
mBottomNavBarVisible = true;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -237,7 +260,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
PixelFormat.TRANSLUCENT);
lp.setTitle("CarNavigationBar");
lp.windowAnimations = 0;
- mWindowManager.addView(mNavigationBarWindow, lp);
+ mWindowManager.addView(mBottomNavigationBarWindow, lp);
}
if (mLeftNavigationBarWindow != null) {
@@ -297,23 +320,11 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
isKeyboardVisible ? View.GONE : View.VISIBLE);
}
- private void updateNavBarForKeyguardContent() {
- if (mNavigationBarView != null) {
- mNavigationBarView.showKeyguardButtons();
- }
- if (mLeftNavigationBarView != null) {
- mLeftNavigationBarView.showKeyguardButtons();
- }
- if (mRightNavigationBarView != null) {
- mRightNavigationBarView.showKeyguardButtons();
- }
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(" mTaskStackListener=");
- pw.println(mFacetButtonTaskStackListener.get());
- pw.print(" mNavigationBarView=");
- pw.println(mNavigationBarView);
+ pw.println(mFacetButtonTaskStackListenerLazy.get());
+ pw.print(" mBottomNavigationBarView=");
+ pw.println(mBottomNavigationBarView);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
index 6bed69bdee88..6f288439ddeb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
@@ -24,8 +24,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.R;
-import com.android.systemui.statusbar.car.hvac.HvacController;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
+import com.android.systemui.navigationbar.car.hvac.HvacController;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -38,6 +37,7 @@ public class CarNavigationBarController {
private final Context mContext;
private final NavigationBarViewFactory mNavigationBarViewFactory;
+ private final Lazy<CarFacetButtonController> mCarFacetButtonControllerLazy;
private final Lazy<HvacController> mHvacControllerLazy;
private boolean mShowBottom;
@@ -58,9 +58,11 @@ public class CarNavigationBarController {
@Inject
public CarNavigationBarController(Context context,
NavigationBarViewFactory navigationBarViewFactory,
+ Lazy<CarFacetButtonController> carFacetButtonControllerLazy,
Lazy<HvacController> hvacControllerLazy) {
mContext = context;
mNavigationBarViewFactory = navigationBarViewFactory;
+ mCarFacetButtonControllerLazy = carFacetButtonControllerLazy;
mHvacControllerLazy = hvacControllerLazy;
// Read configuration.
@@ -129,9 +131,7 @@ public class CarNavigationBarController {
@NonNull
public CarNavigationBarView getTopBar(boolean isSetUp) {
mTopView = mNavigationBarViewFactory.getTopBar(isSetUp);
- mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
- mTopView.setNotificationsPanelController(mNotificationsShadeController);
- addTemperatureViewToController(mTopView);
+ setupBar(mTopView, mTopBarTouchListener, mNotificationsShadeController);
return mTopView;
}
@@ -143,9 +143,7 @@ public class CarNavigationBarController {
}
mBottomView = mNavigationBarViewFactory.getBottomBar(isSetUp);
- mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
- mBottomView.setNotificationsPanelController(mNotificationsShadeController);
- addTemperatureViewToController(mBottomView);
+ setupBar(mBottomView, mBottomBarTouchListener, mNotificationsShadeController);
return mBottomView;
}
@@ -157,9 +155,7 @@ public class CarNavigationBarController {
}
mLeftView = mNavigationBarViewFactory.getLeftBar(isSetUp);
- mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
- mLeftView.setNotificationsPanelController(mNotificationsShadeController);
- addTemperatureViewToController(mLeftView);
+ setupBar(mLeftView, mLeftBarTouchListener, mNotificationsShadeController);
return mLeftView;
}
@@ -171,12 +167,18 @@ public class CarNavigationBarController {
}
mRightView = mNavigationBarViewFactory.getRightBar(isSetUp);
- mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
- mRightView.setNotificationsPanelController(mNotificationsShadeController);
- addTemperatureViewToController(mRightView);
+ setupBar(mRightView, mRightBarTouchListener, mNotificationsShadeController);
return mRightView;
}
+ private void setupBar(CarNavigationBarView view, View.OnTouchListener statusBarTouchListener,
+ NotificationsShadeController notifShadeController) {
+ view.setStatusBarWindowTouchListener(statusBarTouchListener);
+ view.setNotificationsPanelController(notifShadeController);
+ mCarFacetButtonControllerLazy.get().addAllFacetButtons(view);
+ mHvacControllerLazy.get().addTemperatureViewToController(view);
+ }
+
/** Sets a touch listener for the top navigation bar. */
public void registerTopBarTouchListener(View.OnTouchListener listener) {
mTopBarTouchListener = listener;
@@ -290,17 +292,6 @@ public class CarNavigationBarController {
void togglePanel();
}
- private void addTemperatureViewToController(View v) {
- if (v instanceof TemperatureView) {
- mHvacControllerLazy.get().addHvacTextView((TemperatureView) v);
- } else if (v instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) v;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- addTemperatureViewToController(viewGroup.getChildAt(i));
- }
- }
- }
-
private void checkAllBars(boolean isSetUp) {
mTopView = getTopBar(isSetUp);
mBottomView = getBottomBar(isSetUp);
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java
index 41914d212ee9..fd9c488278ba 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,42 +14,45 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
import android.car.VehicleUnit;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
-import android.content.Context;
-import android.os.Handler;
import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.car.CarServiceProvider;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* Manages the connection to the Car service and delegates value changes to the registered
* {@link TemperatureView}s
*/
+@Singleton
public class HvacController {
-
public static final String TAG = "HvacController";
- public static final int BIND_TO_HVAC_RETRY_DELAY = 5000;
- private Context mContext;
- private Handler mHandler;
- private Car mCar;
+ private final CarServiceProvider mCarServiceProvider;
+ private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
+
private CarHvacManager mHvacManager;
private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
@@ -85,22 +88,20 @@ public class HvacController {
}
};
- private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
- if (!ready) {
- return;
- }
- try {
- mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
- mHvacManager.registerCallback(mHardwareCallback);
- initComponents();
- } catch (Exception e) {
- Log.e(TAG, "Failed to correctly connect to HVAC", e);
- }
- };
+ private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
+ car -> {
+ try {
+ mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
+ mHvacManager.registerCallback(mHardwareCallback);
+ initComponents();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to correctly connect to HVAC", e);
+ }
+ };
@Inject
- public HvacController(Context context) {
- mContext = context;
+ public HvacController(CarServiceProvider carServiceProvider) {
+ mCarServiceProvider = carServiceProvider;
}
/**
@@ -108,15 +109,16 @@ public class HvacController {
* ({@link CarHvacManager}) will happen on the same thread this method was called from.
*/
public void connectToCarService() {
- mHandler = new Handler();
- mCar = Car.createCar(mContext, /* handler= */ mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- mCarServiceLifecycleListener);
+ mCarServiceProvider.addListener(mCarServiceLifecycleListener);
}
/**
* Add component to list and initialize it if the connection is up.
*/
- public void addHvacTextView(TemperatureView temperatureView) {
+ private void addHvacTextView(TemperatureView temperatureView) {
+ if (mRegisteredViews.contains(temperatureView)) {
+ return;
+ }
HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId());
if (!mTempComponents.containsKey(hvacKey)) {
@@ -124,6 +126,8 @@ public class HvacController {
}
mTempComponents.get(hvacKey).add(temperatureView);
initComponent(temperatureView);
+
+ mRegisteredViews.add(temperatureView);
}
private void initComponents() {
@@ -169,6 +173,22 @@ public class HvacController {
*/
public void removeAllComponents() {
mTempComponents.clear();
+ mRegisteredViews.clear();
+ }
+
+ /**
+ * Iterate through a view, looking for {@link TemperatureView} instances and add them to the
+ * controller if found.
+ */
+ public void addTemperatureViewToController(View v) {
+ if (v instanceof TemperatureView) {
+ addHvacTextView((TemperatureView) v);
+ } else if (v instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) v;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ addTemperatureViewToController(viewGroup.getChildAt(i));
+ }
+ }
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java
index 17ef3c0204af..ad4fcd9b67da 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureTextView.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
import android.content.Context;
import android.content.res.TypedArray;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java
index c17da1848a8f..963f3184c40d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/TemperatureView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.car.hvac;
+package com.android.systemui.navigationbar.car.hvac;
/**
* Interface for Views that display temperature HVAC properties
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 78ac96020bae..10527b231169 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -57,15 +57,14 @@ import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.BatteryMeterView;
-import com.android.systemui.CarSystemUIFactory;
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.fragments.FragmentHostManager;
@@ -73,9 +72,7 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.navigationbar.car.CarFacetButtonController;
import com.android.systemui.navigationbar.car.CarNavigationBarController;
-import com.android.systemui.navigationbar.car.CarNavigationBarView;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.car.CarQSFragment;
@@ -164,20 +161,20 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private float mBackgroundAlphaDiff;
private float mInitialBackgroundAlpha;
+ private final Lazy<FullscreenUserSwitcher> mFullscreenUserSwitcherLazy;
private FullscreenUserSwitcher mFullscreenUserSwitcher;
private CarBatteryController mCarBatteryController;
private BatteryMeterView mBatteryMeterView;
private Drawable mNotificationPanelBackground;
- private ViewGroup mTopNavigationBarContainer;
- private CarNavigationBarView mTopNavigationBarView;
-
private final Object mQueueLock = new Object();
private final CarNavigationBarController mCarNavigationBarController;
- private CarFacetButtonController mCarFacetButtonController;
+ private final Lazy<DrivingStateHelper> mDrivingStateHelperLazy;
+ private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
+ private final CarServiceProvider mCarServiceProvider;
+
private DeviceProvisionedController mDeviceProvisionedController;
- private boolean mDeviceIsSetUpForUser = true;
private DrivingStateHelper mDrivingStateHelper;
private PowerManagerHelper mPowerManagerHelper;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -311,6 +308,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
ViewMediatorCallback viewMediatorCallback,
DismissCallbackRegistry dismissCallbackRegistry,
/* Car Settings injected components. */
+ CarServiceProvider carServiceProvider,
+ Lazy<DrivingStateHelper> drivingStateHelperLazy,
+ Lazy<PowerManagerHelper> powerManagerHelperLazy,
+ Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
CarNavigationBarController carNavigationBarController) {
super(
context,
@@ -384,16 +385,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
viewMediatorCallback,
dismissCallbackRegistry);
mScrimController = scrimController;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mCarServiceProvider = carServiceProvider;
+ mDrivingStateHelperLazy = drivingStateHelperLazy;
+ mPowerManagerHelperLazy = powerManagerHelperLazy;
+ mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
mCarNavigationBarController = carNavigationBarController;
}
@Override
public void start() {
- // get the provisioned state before calling the parent class since it's that flow that
- // builds the nav bar
- mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- mDeviceIsSetUpForUser = mDeviceProvisionedController.isCurrentUserSetup();
-
// Need to initialize screen lifecycle before calling super.start - before switcher is
// created.
mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -431,52 +432,20 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
createBatteryController();
mCarBatteryController.startListening();
- mDeviceProvisionedController.addCallback(
- new DeviceProvisionedController.DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- mHandler.post(() -> resetSystemBarsIfNecessary());
- }
-
- @Override
- public void onUserSwitched() {
- mHandler.post(() -> resetSystemBarsIfNecessary());
- }
- });
-
// Used by onDrivingStateChanged and it can be called inside
// DrivingStateHelper.connectToCarService()
mSwitchToGuestTimer = new SwitchToGuestTimer(mContext);
// Register a listener for driving state changes.
- mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged);
+ mDrivingStateHelper = mDrivingStateHelperLazy.get();
+ mDrivingStateHelper.setCarDrivingStateEventListener(this::onDrivingStateChanged);
mDrivingStateHelper.connectToCarService();
- mPowerManagerHelper = new PowerManagerHelper(mContext, mCarPowerStateListener);
+ mPowerManagerHelper = mPowerManagerHelperLazy.get();
+ mPowerManagerHelper.setCarPowerStateListener(mCarPowerStateListener);
mPowerManagerHelper.connectToCarService();
}
- private void resetSystemBarsIfNecessary() {
- boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
- if (mDeviceIsSetUpForUser != currentUserSetup) {
- mDeviceIsSetUpForUser = currentUserSetup;
- resetSystemBars();
- }
- }
-
- /**
- * Remove all content from navbars and rebuild them. Used to allow for different nav bars
- * before and after the device is provisioned. . Also for change of density and font size.
- */
- private void resetSystemBars() {
- mCarFacetButtonController.removeAll();
-
- buildNavBarContent();
- // CarFacetButtonController was reset therefore we need to re-add the status bar elements
- // to the controller.
- mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow);
- }
-
/**
* Allows for showing or hiding just the navigation bars. This is indented to be used when
* the full screen user selector is shown.
@@ -490,23 +459,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
public boolean hideKeyguard() {
boolean result = super.hideKeyguard();
- mCarNavigationBarController.hideAllKeyguardButtons(mDeviceIsSetUpForUser);
+ mCarNavigationBarController.hideAllKeyguardButtons(
+ mDeviceProvisionedController.isCurrentUserSetup());
return result;
}
@Override
public void showKeyguard() {
super.showKeyguard();
- mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
+ mCarNavigationBarController.showAllKeyguardButtons(
+ mDeviceProvisionedController.isCurrentUserSetup());
}
@Override
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
super.makeStatusBarView(result);
- CarSystemUIFactory factory = SystemUIFactory.getInstance();
- mCarFacetButtonController = factory.getCarDependencyComponent()
- .getCarFacetButtonController();
mNotificationPanelBackground = getDefaultWallpaper();
mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
@@ -562,7 +530,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
new HandleBarCloseNotificationGestureListener());
mTopNavBarNotificationTouchListener = (v, event) -> {
- if (!mDeviceIsSetUpForUser) {
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) {
return true;
}
boolean consumed = openGestureDetector.onTouchEvent(event);
@@ -592,20 +560,13 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
});
CarNotificationListener carNotificationListener = new CarNotificationListener();
mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
- // This can take time if car service is not ready up to this time.
- // TODO(b/142808072) Refactor CarUxRestrictionManagerWrapper to allow setting
- // CarUxRestrictionsManager later and switch to Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT.
- Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
- (car, ready) -> {
- if (!ready) {
- return;
- }
- CarUxRestrictionsManager carUxRestrictionsManager =
- (CarUxRestrictionsManager)
- car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
- mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
- carUxRestrictionsManager);
- });
+ mCarServiceProvider.addListener(car -> {
+ CarUxRestrictionsManager carUxRestrictionsManager =
+ (CarUxRestrictionsManager)
+ car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+ mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
+ carUxRestrictionsManager);
+ });
mNotificationDataManager = new NotificationDataManager();
mNotificationDataManager.setOnUnseenCountUpdateListener(
@@ -614,7 +575,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
boolean hasUnseen =
mNotificationDataManager.getUnseenNotificationCount() > 0;
mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
- mDeviceIsSetUpForUser, hasUnseen);
+ mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
}
});
@@ -868,14 +829,14 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
- mTopNavigationBarContainer = mStatusBarWindow
- .findViewById(R.id.car_top_navigation_bar_container);
-
- buildNavBarContent();
+ registerNavBarListeners();
}
- private void buildNavBarContent() {
- buildTopBar();
+ private void registerNavBarListeners() {
+ // In CarStatusBar, navigation bars are built by NavigationBar.java
+ // Instead, we register necessary callbacks to the navigation bar controller.
+ mCarNavigationBarController.registerTopBarTouchListener(
+ mTopNavBarNotificationTouchListener);
mCarNavigationBarController.registerBottomBarTouchListener(
mNavBarNotificationTouchListener);
@@ -889,14 +850,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mCarNavigationBarController.registerNotificationController(() -> togglePanel());
}
- private void buildTopBar() {
- mTopNavigationBarContainer.removeAllViews();
- mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
- mCarNavigationBarController.registerTopBarTouchListener(
- mTopNavBarNotificationTouchListener);
- mTopNavigationBarContainer.addView(mTopNavigationBarView);
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
//When executing dump() function simultaneously, we need to serialize them
@@ -908,8 +861,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
+ "," + mStackScroller.getScrollY());
}
- pw.print(" mCarFacetButtonController=");
- pw.println(mCarFacetButtonController);
pw.print(" mFullscreenUserSwitcher=");
pw.println(mFullscreenUserSwitcher);
pw.print(" mCarBatteryController=");
@@ -974,8 +925,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
UserSwitcherController userSwitcherController =
Dependency.get(UserSwitcherController.class);
if (userSwitcherController.useFullscreenUserSwitcher()) {
- mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
- mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
+ mFullscreenUserSwitcher = mFullscreenUserSwitcherLazy.get();
+ mFullscreenUserSwitcher.setStatusBar(this);
+ mFullscreenUserSwitcher.setContainer(
+ mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
} else {
super.createUserSwitcher();
}
@@ -1058,7 +1011,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
public void onDensityOrFontScaleChanged() {
super.onDensityOrFontScaleChanged();
- resetSystemBars();
+ registerNavBarListeners();
// Need to update the background on density changed in case the change was due to night
// mode.
mNotificationPanelBackground = getDefaultWallpaper();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index b9dacc0ded3e..5418ebe5b8de 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -29,6 +29,7 @@ import com.android.systemui.UiOffloadThread;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -179,6 +180,10 @@ public class CarStatusBarModule {
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
DismissCallbackRegistry dismissCallbackRegistry,
+ CarServiceProvider carServiceProvider,
+ Lazy<DrivingStateHelper> drivingStateHelperLazy,
+ Lazy<PowerManagerHelper> powerManagerHelperLazy,
+ Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
CarNavigationBarController carNavigationBarController) {
return new CarStatusBar(
context,
@@ -250,6 +255,10 @@ public class CarStatusBarModule {
statusBarKeyguardViewManager,
viewMediatorCallback,
dismissCallbackRegistry,
+ carServiceProvider,
+ drivingStateHelperLazy,
+ powerManagerHelperLazy,
+ fullscreenUserSwitcherLazy,
carNavigationBarController);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
index ec72ee74f59a..ec4643302a05 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.UserHandle;
@@ -36,15 +37,21 @@ import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainResources;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
/**
* A helper class displays an unlock dialog and receives broadcast about detecting trusted device
* & unlocking state to show the appropriate message on the dialog.
*/
+@Singleton
class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName();
private final Context mContext;
+ private final Resources mResources;
private final WindowManager mWindowManager;
private final UserManager mUserManager;
private final WindowManager.LayoutParams mParams;
@@ -60,10 +67,13 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
private boolean mIsDialogShowing;
private OnHideListener mOnHideListener;
- CarTrustAgentUnlockDialogHelper(Context context) {
+ @Inject
+ CarTrustAgentUnlockDialogHelper(Context context, @MainResources Resources resources,
+ UserManager userManager, WindowManager windowManager) {
mContext = context;
- mUserManager = mContext.getSystemService(UserManager.class);
- mWindowManager = mContext.getSystemService(WindowManager.class);
+ mResources = resources;
+ mUserManager = userManager;
+ mWindowManager = windowManager;
mParams = createLayoutParams();
mFilter = getIntentFilter();
@@ -125,7 +135,7 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
* @param listener listener that listens to dialog hide
*/
void showUnlockDialogAfterDelay(int uid, OnHideListener listener) {
- long delayMillis = mContext.getResources().getInteger(R.integer.unlock_dialog_delay_ms);
+ long delayMillis = mResources.getInteger(R.integer.unlock_dialog_delay_ms);
showUnlockDialogAfterDelay(uid, delayMillis, listener);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
index cd87e78e4be9..60934ab11532 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
@@ -17,31 +17,43 @@
package com.android.systemui.statusbar.car;
import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarDrivingStateManager;
import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener;
-import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
+import com.android.systemui.car.CarServiceProvider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Helper class for connecting to the {@link CarDrivingStateManager} and listening for driving state
* changes.
*/
+@Singleton
public class DrivingStateHelper {
public static final String TAG = "DrivingStateHelper";
- private final Context mContext;
+ private final CarServiceProvider mCarServiceProvider;
+
private CarDrivingStateManager mDrivingStateManager;
- private Car mCar;
private CarDrivingStateEventListener mDrivingStateHandler;
- public DrivingStateHelper(Context context,
- @NonNull CarDrivingStateEventListener drivingStateHandler) {
- mContext = context;
- mDrivingStateHandler = drivingStateHandler;
+ @Inject
+ public DrivingStateHelper(CarServiceProvider carServiceProvider) {
+ mCarServiceProvider = carServiceProvider;
+ }
+
+ /**
+ * Sets the {@link CarDrivingStateEventListener}. Should be set before calling {@link
+ * #connectToCarService()}.
+ */
+ public void setCarDrivingStateEventListener(
+ @NonNull CarDrivingStateEventListener carDrivingStateEventListener) {
+ mDrivingStateHandler = carDrivingStateEventListener;
}
/**
@@ -64,25 +76,22 @@ public class DrivingStateHelper {
* Establishes connection with the Car service.
*/
public void connectToCarService() {
- mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- mCarServiceLifecycleListener);
+ mCarServiceProvider.addListener(mCarServiceLifecycleListener);
}
- private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
- if (!ready) {
- return;
- }
- logD("Car Service connected");
- mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
- Car.CAR_DRIVING_STATE_SERVICE);
- if (mDrivingStateManager != null) {
- mDrivingStateManager.registerListener(mDrivingStateHandler);
- mDrivingStateHandler.onDrivingStateChanged(
- mDrivingStateManager.getCurrentCarDrivingState());
- } else {
- Log.e(TAG, "CarDrivingStateService service not available");
- }
- };
+ private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
+ car -> {
+ logD("Car Service connected");
+ mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
+ Car.CAR_DRIVING_STATE_SERVICE);
+ if (mDrivingStateManager != null) {
+ mDrivingStateManager.registerListener(mDrivingStateHandler);
+ mDrivingStateHandler.onDrivingStateChanged(
+ mDrivingStateManager.getCurrentCarDrivingState());
+ } else {
+ Log.e(TAG, "CarDrivingStateService service not available");
+ }
+ };
private void logD(String message) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 31aced02b15e..b188dc3949f2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -35,24 +36,34 @@ import android.view.ViewStub;
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.qualifiers.MainResources;
import com.android.systemui.statusbar.car.CarTrustAgentUnlockDialogHelper.OnHideListener;
import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Manages the fullscreen user switcher.
*/
+@Singleton
public class FullscreenUserSwitcher {
private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
// Because user 0 is headless, user count for single user is 2
private static final int NUMBER_OF_BACKGROUND_USERS = 1;
- private final UserGridRecyclerView mUserGridView;
- private final View mParent;
- private final int mShortAnimDuration;
- private final CarStatusBar mStatusBar;
+
private final Context mContext;
+ private final Resources mResources;
private final UserManager mUserManager;
+ private final CarServiceProvider mCarServiceProvider;
+ private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
+ private final int mShortAnimDuration;
+
+ private CarStatusBar mStatusBar;
+ private View mParent;
+ private UserGridRecyclerView mUserGridView;
private CarTrustAgentEnrollmentManager mEnrollmentManager;
- private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
private UserGridRecyclerView.UserRecord mSelectedUser;
private CarUserManagerHelper mCarUserManagerHelper;
private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
@@ -65,37 +76,46 @@ public class FullscreenUserSwitcher {
mContext.unregisterReceiver(mUserUnlockReceiver);
}
};
- private final Car mCar;
- public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
+ @Inject
+ public FullscreenUserSwitcher(
+ Context context,
+ @MainResources Resources resources,
+ UserManager userManager,
+ CarServiceProvider carServiceProvider,
+ CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper) {
+ mContext = context;
+ mResources = resources;
+ mUserManager = userManager;
+ mCarServiceProvider = carServiceProvider;
+ mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
+
+ mShortAnimDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
+ }
+
+ /** Sets the status bar which controls the keyguard. */
+ public void setStatusBar(CarStatusBar statusBar) {
mStatusBar = statusBar;
+ }
+
+ /** Sets the {@link ViewStub} to show the user switcher. */
+ public void setContainer(ViewStub containerStub) {
mParent = containerStub.inflate();
- mContext = context;
View container = mParent.findViewById(R.id.container);
// Initialize user grid.
mUserGridView = container.findViewById(R.id.user_grid);
- GridLayoutManager layoutManager = new GridLayoutManager(context,
- context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ GridLayoutManager layoutManager = new GridLayoutManager(mContext,
+ mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
- mCarUserManagerHelper = new CarUserManagerHelper(context);
- mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext);
- mUserManager = mContext.getSystemService(UserManager.class);
-
- mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- (car, ready) -> {
- if (!ready) {
- return;
- }
- mEnrollmentManager = (CarTrustAgentEnrollmentManager) car
- .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
- });
+ mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+ mCarServiceProvider.addListener(
+ car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
+ Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
- mShortAnimDuration = container.getResources()
- .getInteger(android.R.integer.config_shortAnimTime);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
// User0 is unlocked, switched to the initial user
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
index a27dd341d449..71847bbac9fd 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
@@ -18,33 +18,33 @@ package com.android.systemui.statusbar.car;
import android.annotation.NonNull;
import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.content.Context;
import android.util.Log;
+import com.android.systemui.car.CarServiceProvider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Helper class for connecting to the {@link CarPowerManager} and listening for power state changes.
*/
+@Singleton
public class PowerManagerHelper {
public static final String TAG = "PowerManagerHelper";
- private final Context mContext;
- private final CarPowerStateListener mCarPowerStateListener;
+ private final CarServiceProvider mCarServiceProvider;
- private Car mCar;
private CarPowerManager mCarPowerManager;
+ private CarPowerStateListener mCarPowerStateListener;
- private final CarServiceLifecycleListener mCarServiceLifecycleListener;
+ private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener;
- PowerManagerHelper(Context context, @NonNull CarPowerStateListener listener) {
- mContext = context;
- mCarPowerStateListener = listener;
- mCarServiceLifecycleListener = (car, ready) -> {
- if (!ready) {
- return;
- }
+ @Inject
+ PowerManagerHelper(CarServiceProvider carServiceProvider) {
+ mCarServiceProvider = carServiceProvider;
+ mCarServiceLifecycleListener = car -> {
Log.d(TAG, "Car Service connected");
mCarPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE);
if (mCarPowerManager != null) {
@@ -56,10 +56,16 @@ public class PowerManagerHelper {
}
/**
+ * Sets a {@link CarPowerStateListener}. Should be set before {@link #connectToCarService()}.
+ */
+ void setCarPowerStateListener(@NonNull CarPowerStateListener listener) {
+ mCarPowerStateListener = listener;
+ }
+
+ /**
* Connect to Car service.
*/
void connectToCarService() {
- mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- mCarServiceLifecycleListener);
+ mCarServiceProvider.addListener(mCarServiceLifecycleListener);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
index 76126fcd949c..908aaad71893 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
@@ -35,7 +35,7 @@ import android.widget.TextSwitcher;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
+import com.android.systemui.navigationbar.car.hvac.TemperatureView;
/**
* Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
index 4d6af95b3f9c..5a3443674cf4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
@@ -18,7 +18,7 @@ package com.android.systemui.volume;
import android.content.Context;
-import com.android.systemui.SystemUI;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.VolumeDialog;
@@ -31,12 +31,20 @@ import javax.inject.Singleton;
@Singleton
public class CarVolumeDialogComponent extends VolumeDialogComponent {
+ private CarVolumeDialogImpl mCarVolumeDialog;
+
@Inject
- public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator) {
- super(context, keyguardViewMediator);
+ public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
+ VolumeDialogControllerImpl volumeDialogController,
+ CarServiceProvider carServiceProvider) {
+ super(context, keyguardViewMediator, volumeDialogController);
+ mCarVolumeDialog.setCarServiceProvider(carServiceProvider);
}
+ /** This method is called while calling the super constructor. */
+ @Override
protected VolumeDialog createDefault() {
- return new CarVolumeDialogImpl(mContext);
+ mCarVolumeDialog = new CarVolumeDialogImpl(mContext);
+ return mCarVolumeDialog;
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 09223e8ff4c3..367959ec4972 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -24,7 +24,6 @@ import android.annotation.Nullable;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.car.Car;
-import android.car.Car.CarServiceLifecycleListener;
import android.car.media.CarAudioManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -56,6 +55,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
+import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.plugins.VolumeDialog;
import org.xmlpull.v1.XmlPullParserException;
@@ -95,7 +95,6 @@ public class CarVolumeDialogImpl implements VolumeDialog {
private CustomDialog mDialog;
private RecyclerView mListView;
private CarVolumeItemAdapter mVolumeItemsAdapter;
- private Car mCar;
private CarAudioManager mCarAudioManager;
private boolean mHovering;
private int mCurrentlyDisplayingGroupId;
@@ -147,30 +146,28 @@ public class CarVolumeDialogImpl implements VolumeDialog {
}
};
- private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
- if (!ready) {
- return;
- }
- mExpanded = false;
- mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
- int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
- // Populates volume slider items from volume groups to UI.
- for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
- VolumeItem volumeItem = getVolumeItemForUsages(
- mCarAudioManager.getUsagesForVolumeGroupId(groupId));
- mAvailableVolumeItems.add(volumeItem);
- // The first one is the default item.
- if (groupId == 0) {
- clearAllAndSetupDefaultCarVolumeLineItem(0);
- }
- }
+ private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceOnConnectedListener =
+ car -> {
+ mExpanded = false;
+ mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+ int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
+ // Populates volume slider items from volume groups to UI.
+ for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
+ VolumeItem volumeItem = getVolumeItemForUsages(
+ mCarAudioManager.getUsagesForVolumeGroupId(groupId));
+ mAvailableVolumeItems.add(volumeItem);
+ // The first one is the default item.
+ if (groupId == 0) {
+ clearAllAndSetupDefaultCarVolumeLineItem(0);
+ }
+ }
- // If list is already initiated, update its content.
- if (mVolumeItemsAdapter != null) {
- mVolumeItemsAdapter.notifyDataSetChanged();
- }
- mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
- };
+ // If list is already initiated, update its content.
+ if (mVolumeItemsAdapter != null) {
+ mVolumeItemsAdapter.notifyDataSetChanged();
+ }
+ mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
+ };
public CarVolumeDialogImpl(Context context) {
mContext = context;
@@ -181,6 +178,11 @@ public class CarVolumeDialogImpl implements VolumeDialog {
R.integer.car_volume_dialog_display_hovering_timeout);
}
+ /** Sets a {@link CarServiceProvider} which connects to the audio service. */
+ public void setCarServiceProvider(CarServiceProvider carServiceProvider) {
+ carServiceProvider.addListener(mCarServiceOnConnectedListener);
+ }
+
private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
return carAudioManager.getGroupVolume(volumeGroupId);
}
@@ -196,8 +198,6 @@ public class CarVolumeDialogImpl implements VolumeDialog {
@Override
public void init(int windowType, Callback callback) {
initDialog();
- mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- mCarServiceLifecycleListener);
}
@Override
@@ -205,12 +205,6 @@ public class CarVolumeDialogImpl implements VolumeDialog {
mHandler.removeCallbacksAndMessages(/* token= */ null);
cleanupAudioManager();
- // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup
- // audio manager beforehand.
- if (mCar != null) {
- mCar.disconnect();
- mCar = null;
- }
}
private void initDialog() {
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
index 901d2006eb12..642b1145cb94 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
@@ -31,8 +31,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.navigationbar.car.hvac.HvacController;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.car.hvac.HvacController;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import org.junit.Before;
@@ -41,8 +41,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import dagger.Lazy;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -50,17 +48,17 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private CarNavigationBarController mCarNavigationBar;
private NavigationBarViewFactory mNavigationBarViewFactory;
- private Lazy<HvacController> mHvacControllerLazy;
private TestableResources mTestableResources;
@Mock
+ private CarFacetButtonController mCarFacetButtonController;
+ @Mock
private HvacController mHvacController;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNavigationBarViewFactory = new NavigationBarViewFactory(mContext);
- mHvacControllerLazy = () -> mHvacController;
mTestableResources = mContext.getOrCreateTestableResources();
// Needed to inflate top navigation bar.
@@ -71,7 +69,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testConnectToHvac_callsConnect() {
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
mCarNavigationBar.connectToHvac();
@@ -81,7 +79,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testRemoveAllFromHvac_callsRemoveAll() {
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
mCarNavigationBar.removeAllFromHvac();
@@ -92,7 +90,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetBottomWindow_bottomDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getBottomWindow();
@@ -103,7 +101,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetBottomWindow_bottomEnabled_returnsWindow() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getBottomWindow();
@@ -114,7 +112,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window1 = mCarNavigationBar.getBottomWindow();
ViewGroup window2 = mCarNavigationBar.getBottomWindow();
@@ -126,7 +124,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetLeftWindow_leftDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getLeftWindow();
assertThat(window).isNull();
}
@@ -135,7 +133,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetLeftWindow_leftEnabled_returnsWindow() {
mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getLeftWindow();
@@ -146,7 +144,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() {
mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window1 = mCarNavigationBar.getLeftWindow();
ViewGroup window2 = mCarNavigationBar.getLeftWindow();
@@ -158,7 +156,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetRightWindow_rightDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getRightWindow();
@@ -169,7 +167,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetRightWindow_rightEnabled_returnsWindow() {
mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getRightWindow();
@@ -180,7 +178,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() {
mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window1 = mCarNavigationBar.getRightWindow();
ViewGroup window2 = mCarNavigationBar.getRightWindow();
@@ -192,7 +190,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetBottomWindowVisibility_setTrue_isVisible() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getBottomWindow();
mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE);
@@ -204,7 +202,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetBottomWindowVisibility_setFalse_isGone() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getBottomWindow();
mCarNavigationBar.setBottomWindowVisibility(View.GONE);
@@ -216,7 +214,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetLeftWindowVisibility_setTrue_isVisible() {
mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getLeftWindow();
mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE);
@@ -228,7 +226,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetLeftWindowVisibility_setFalse_isGone() {
mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getLeftWindow();
mCarNavigationBar.setLeftWindowVisibility(View.GONE);
@@ -240,7 +238,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetRightWindowVisibility_setTrue_isVisible() {
mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getRightWindow();
mCarNavigationBar.setRightWindowVisibility(View.VISIBLE);
@@ -252,7 +250,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testSetRightWindowVisibility_setFalse_isGone() {
mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
ViewGroup window = mCarNavigationBar.getRightWindow();
mCarNavigationBar.setRightWindowVisibility(View.GONE);
@@ -264,7 +262,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
@@ -279,7 +277,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
@@ -292,7 +290,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testRegisterNotificationController_createViewFirst_registrationSuccessful() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
CarNavigationBarController.NotificationsShadeController controller =
@@ -309,7 +307,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testRegisterNotificationController_registerFirst_registrationSuccessful() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
mCarNavigationBar.registerNotificationController(
mock(CarNavigationBarController.NotificationsShadeController.class));
@@ -324,7 +322,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
@@ -337,7 +335,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
@@ -350,7 +348,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
@@ -365,7 +363,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
@@ -380,7 +378,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
@@ -395,7 +393,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mHvacControllerLazy);
+ () -> mCarFacetButtonController, () -> mHvacController);
CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java
new file mode 100644
index 000000000000..a71d1db3ee70
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.navigationbar.car.hvac;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.hardware.hvac.CarHvacManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class HvacControllerTest extends SysuiTestCase {
+
+ private static final int PROPERTY_ID = 1;
+ private static final int AREA_ID = 1;
+ private static final float VALUE = 72.0f;
+
+ private HvacController mHvacController;
+ private CarServiceProvider mCarServiceProvider;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarHvacManager mCarHvacManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager);
+
+ mCarServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(mCarServiceProvider);
+ mHvacController.connectToCarService();
+ }
+
+ @Test
+ public void connectToCarService_registersCallback() {
+ verify(mCarHvacManager).registerCallback(any());
+ }
+
+ @Test
+ public void addTemperatureViewToController_usingTemperatureView_registersView() {
+ TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ mHvacController.addTemperatureViewToController(v);
+
+ verify(v).setTemp(VALUE);
+ }
+
+ @Test
+ public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
+ TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ mHvacController.addTemperatureViewToController(v);
+ verify(v).setTemp(VALUE);
+ resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+
+ mHvacController.addTemperatureViewToController(v);
+ verify(v, never()).setTemp(VALUE);
+ }
+
+ @Test
+ public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
+ TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ mHvacController.addTemperatureViewToController(v1);
+ verify(v1).setTemp(VALUE);
+
+ TemperatureTextView v2 = setupMockTemperatureTextView(
+ PROPERTY_ID + 1,
+ AREA_ID + 1,
+ VALUE + 1);
+ mHvacController.addTemperatureViewToController(v2);
+ verify(v2).setTemp(VALUE + 1);
+ }
+
+ @Test
+ public void removeAllComponents_ableToRegisterSameView() {
+ TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ mHvacController.addTemperatureViewToController(v);
+ verify(v).setTemp(VALUE);
+
+ mHvacController.removeAllComponents();
+ resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+
+ mHvacController.addTemperatureViewToController(v);
+ verify(v).setTemp(VALUE);
+ }
+
+ private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId,
+ float value) {
+ TemperatureTextView v = mock(TemperatureTextView.class);
+ resetTemperatureView(v, propertyId, areaId);
+ when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true);
+ when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value);
+ return v;
+ }
+
+ private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) {
+ reset(view);
+ when(view.getPropertyId()).thenReturn(propertyId);
+ when(view.getAreaId()).thenReturn(areaId);
+ }
+}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index af96982f5426..4a50210d1a60 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -162,12 +162,12 @@ public class ExternalStorageProvider extends FileSystemProvider {
final String title;
final UUID storageUuid;
if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
- // We currently only support a single emulated volume mounted at
+ // We currently only support a single emulated volume per user mounted at
// a time, and it's always considered the primary
if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
rootId = ROOT_ID_PRIMARY_EMULATED;
- if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
+ if (volume.isPrimaryEmulatedForUser(userId)) {
// This is basically the user's primary device storage.
// Use device name for the volume since this is likely same thing
// the user sees when they mount their phone on another device.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index df30c248c00c..4b4861a01898 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -212,15 +212,21 @@ public class BluetoothEventManager {
}
private void dispatchAudioModeChanged() {
- mDeviceManager.dispatchAudioModeChanged();
+ for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
+ cachedDevice.onAudioModeChanged();
+ }
for (BluetoothCallback callback : mCallbacks) {
callback.onAudioModeChanged();
}
}
- private void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
+ @VisibleForTesting
+ void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
int bluetoothProfile) {
- mDeviceManager.onActiveDeviceChanged(activeDevice, bluetoothProfile);
+ for (CachedBluetoothDevice cachedDevice : mDeviceManager.getCachedDevicesCopy()) {
+ boolean isActive = Objects.equals(cachedDevice, activeDevice);
+ cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
+ }
for (BluetoothCallback callback : mCallbacks) {
callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index f24319938e9e..9f71033de758 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -26,7 +26,6 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Objects;
/**
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -229,14 +228,6 @@ public class CachedBluetoothDeviceManager {
}
}
- public synchronized void onActiveDeviceChanged(CachedBluetoothDevice activeDevice,
- int bluetoothProfile) {
- for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
- boolean isActive = Objects.equals(cachedDevice, activeDevice);
- cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
- }
- }
-
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
cachedDevice, int state) {
return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
@@ -257,12 +248,6 @@ public class CachedBluetoothDeviceManager {
}
}
- public synchronized void dispatchAudioModeChanged() {
- for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
- cachedDevice.onAudioModeChanged();
- }
- }
-
private void log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
index e8245082f8ef..5b9281cb9d2e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
@@ -30,10 +30,12 @@ import com.android.internal.logging.nano.MetricsProto;
public class EventLogWriter implements LogWriter {
@Override
- public void visible(Context context, int source, int category) {
+ public void visible(Context context, int source, int category, int latency) {
final LogMaker logMaker = new LogMaker(category)
.setType(MetricsProto.MetricsEvent.TYPE_OPEN)
- .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ latency);
MetricsLogger.action(logMaker);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
index f1876883a336..9d9c17f3b443 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
@@ -26,7 +26,7 @@ public interface LogWriter {
/**
* Logs a visibility event when view becomes visible.
*/
- void visible(Context context, int source, int category);
+ void visible(Context context, int source, int category, int latency);
/**
* Logs a visibility event when view becomes hidden.
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 8cc3b5a3f37a..5cf44e1f6725 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -67,9 +67,16 @@ public class MetricsFeatureProvider {
SettingsEnums.PAGE_UNKNOWN);
}
- public void visible(Context context, int source, int category) {
+ /**
+ * Logs an event when target page is visible.
+ *
+ * @param source from this page id to target page
+ * @param category the target page id
+ * @param latency the latency of target page creation
+ */
+ public void visible(Context context, int source, int category, int latency) {
for (LogWriter writer : mLoggerWriters) {
- writer.visible(context, source, category);
+ writer.visible(context, source, category, latency);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 8090169a4245..1c6287907fbd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -23,15 +23,16 @@ import android.content.Intent;
import android.os.SystemClock;
import androidx.lifecycle.Lifecycle.Event;
-import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnAttach;
/**
* Logs visibility change of a fragment.
*/
-public class VisibilityLoggerMixin implements LifecycleObserver {
+public class VisibilityLoggerMixin implements LifecycleObserver, OnAttach {
private static final String TAG = "VisibilityLoggerMixin";
@@ -39,24 +40,36 @@ public class VisibilityLoggerMixin implements LifecycleObserver {
private MetricsFeatureProvider mMetricsFeature;
private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
- private long mVisibleTimestamp;
+ private long mTimestamp;
public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
mMetricsCategory = metricsCategory;
mMetricsFeature = metricsFeature;
}
+ @Override
+ public void onAttach() {
+ mTimestamp = SystemClock.elapsedRealtime();
+ }
+
@OnLifecycleEvent(Event.ON_RESUME)
public void onResume() {
- mVisibleTimestamp = SystemClock.elapsedRealtime();
- if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
- mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
+ if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+ return;
+ }
+ if (mTimestamp != 0L) {
+ final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+ mMetricsFeature.visible(null /* context */, mSourceMetricsCategory,
+ mMetricsCategory, elapse);
+ } else {
+ mMetricsFeature.visible(null /* context */, mSourceMetricsCategory,
+ mMetricsCategory, 0);
}
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onPause() {
- mVisibleTimestamp = 0;
+ mTimestamp = 0;
if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
mMetricsFeature.hidden(null /* context */, mMetricsCategory);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
index 56de280a0049..f87c88695686 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
@@ -94,11 +94,14 @@ public class Lifecycle extends LifecycleRegistry {
}
}
+ /**
+ * Pass all onAttach event to {@link LifecycleObserver}.
+ */
public void onAttach(Context context) {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnAttach) {
- ((OnAttach) observer).onAttach(context);
+ ((OnAttach) observer).onAttach();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
index e28c38736639..1e7d01c15fbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
@@ -15,12 +15,12 @@
*/
package com.android.settingslib.core.lifecycle.events;
-import android.content.Context;
-
/**
- * @deprecated pass {@link Context} in constructor instead
+ * An Interface used by {@link LifecycleObserver} which changes to onAttach state.
*/
-@Deprecated
public interface OnAttach {
- void onAttach(Context context);
+ /**
+ * Called when {@link LifecycleObserver} is entering onAttach
+ */
+ void onAttach();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 2c70cbbe6ecb..ba1dc64ce1e6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib.bluetooth;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -41,6 +43,9 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class BluetoothEventManagerTest {
@@ -54,10 +59,24 @@ public class BluetoothEventManagerTest {
private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock
private BluetoothDevice mBluetoothDevice;
+ @Mock
+ private HeadsetProfile mHfpProfile;
+ @Mock
+ private A2dpProfile mA2dpProfile;
+ @Mock
+ private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private BluetoothDevice mDevice1;
+ @Mock
+ private BluetoothDevice mDevice2;
+ @Mock
+ private LocalBluetoothProfileManager mLocalProfileManager;
private Context mContext;
private Intent mIntent;
private BluetoothEventManager mBluetoothEventManager;
+ private CachedBluetoothDevice mCachedDevice1;
+ private CachedBluetoothDevice mCachedDevice2;
@Before
public void setUp() {
@@ -67,6 +86,12 @@ public class BluetoothEventManagerTest {
mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter,
mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+ when(mHfpProfile.isProfileReady()).thenReturn(true);
+ when(mA2dpProfile.isProfileReady()).thenReturn(true);
+ when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+
+ mCachedDevice1 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1);
+ mCachedDevice2 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2);
}
@Test
@@ -194,4 +219,129 @@ public class BluetoothEventManagerTest {
verify(mBluetoothCallback, never()).onAclConnectionStateChanged(mCachedBluetoothDevice,
BluetoothAdapter.STATE_CONNECTED);
}
+
+ /**
+ * Test to verify onActiveDeviceChanged().
+ */
+ @Test
+ public void dispatchActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
+ final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ cachedDevices.add(mCachedDevice1);
+ cachedDevices.add(mCachedDevice2);
+
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+
+ // Connect both devices for A2DP and HFP
+ mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+
+ // Verify that both devices are connected and none is Active
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+
+ // The first device is active for A2DP, the second device is active for HFP
+ mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
+ mBluetoothEventManager
+ .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+ // The first device is active for A2DP and HFP
+ mBluetoothEventManager
+ .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+
+ // The second device is active for A2DP and HFP
+ mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.A2DP);
+ mBluetoothEventManager
+ .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+ // No active device for A2DP
+ mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+
+ // No active device for HFP
+ mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ }
+
+ /**
+ * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
+ */
+ @Test
+ public void dispatchActiveDeviceChanged_withA2dpAndHearingAid() {
+ final List<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ cachedDevices.add(mCachedDevice1);
+ cachedDevices.add(mCachedDevice2);
+
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+
+ // Connect device1 for A2DP and HFP and device2 for Hearing Aid
+ mCachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ mCachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+ // Verify that both devices are connected and none is Active
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+
+ // The first device is active for A2DP and HFP
+ mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.A2DP);
+ mBluetoothEventManager
+ .dispatchActiveDeviceChanged(mCachedDevice1, BluetoothProfile.HEADSET);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+
+ // The second device is active for Hearing Aid and the first device is not active
+ mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.A2DP);
+ mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEADSET);
+ mBluetoothEventManager
+ .dispatchActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEARING_AID);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();
+
+ // No active device for Hearing Aid
+ mBluetoothEventManager.dispatchActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
+ assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 806f22f4861a..aef7fae8ee0b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
import org.junit.Before;
@@ -50,8 +49,6 @@ public class CachedBluetoothDeviceManagerTest {
private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
- private final static String DEVICE_SUMMARY_1 = "summary 1";
- private final static String DEVICE_SUMMARY_2 = "summary 2";
private final static long HISYNCID1 = 10;
private final static long HISYNCID2 = 11;
private final BluetoothClass DEVICE_CLASS_1 =
@@ -401,124 +398,4 @@ public class CachedBluetoothDeviceManagerTest {
when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
assertThat(mCachedDeviceManager.onDeviceDisappeared(cachedDevice1)).isTrue();
}
-
- /**
- * Test to verify onActiveDeviceChanged().
- */
- @Test
- public void onActiveDeviceChanged_connectedDevices_activeDeviceChanged() {
- CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
- assertThat(cachedDevice1).isNotNull();
- CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
- assertThat(cachedDevice2).isNotNull();
-
- when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-
- // Connect both devices for A2DP and HFP
- cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- cachedDevice2.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- cachedDevice2.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
-
- // Verify that both devices are connected and none is Active
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-
- // The first device is active for A2DP, the second device is active for HFP
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
- // The first device is active for A2DP and HFP
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
-
- // The second device is active for A2DP and HFP
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.A2DP);
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEADSET);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
- // No active device for A2DP
- mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
-
- // No active device for HFP
- mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- }
-
- /**
- * Test to verify onActiveDeviceChanged() with A2DP and Hearing Aid.
- */
- @Test
- public void onActiveDeviceChanged_withA2dpAndHearingAid() {
- CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
- assertThat(cachedDevice1).isNotNull();
- CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
- assertThat(cachedDevice2).isNotNull();
-
- when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-
- // Connect device1 for A2DP and HFP and device2 for Hearing Aid
- cachedDevice1.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
- cachedDevice1.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
- cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
-
- // Verify that both devices are connected and none is Active
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-
- // The first device is active for A2DP and HFP
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.A2DP);
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1, BluetoothProfile.HEADSET);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isTrue();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isTrue();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
-
- // The second device is active for Hearing Aid and the first device is not active
- mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.A2DP);
- mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEADSET);
- mCachedDeviceManager.onActiveDeviceChanged(cachedDevice2, BluetoothProfile.HEARING_AID);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isTrue();
-
- // No active device for Hearing Aid
- mCachedDeviceManager.onActiveDeviceChanged(null, BluetoothProfile.HEARING_AID);
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice1.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
- assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
- }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
index 097db176a99a..f070a37aa659 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
@@ -65,7 +65,7 @@ public class VisibilityLoggerMixinTest {
verify(mMetricsFeature, times(1))
.visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN),
- eq(TestInstrumentable.TEST_METRIC));
+ eq(TestInstrumentable.TEST_METRIC), anyInt());
}
@Test
@@ -80,7 +80,7 @@ public class VisibilityLoggerMixinTest {
verify(mMetricsFeature, times(1))
.visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES),
- eq(TestInstrumentable.TEST_METRIC));
+ eq(TestInstrumentable.TEST_METRIC), anyInt());
}
@Test
@@ -118,7 +118,8 @@ public class VisibilityLoggerMixinTest {
TestActivity testActivity = ac.get();
MockitoAnnotations.initMocks(testActivity);
ac.create().start().resume();
- verify(testActivity.mMetricsFeatureProvider, times(1)).visible(any(), anyInt(), anyInt());
+ verify(testActivity.mMetricsFeatureProvider, times(1)).visible(any(), anyInt(), anyInt(),
+ anyInt());
ac.pause().stop().destroy();
verify(testActivity.mMetricsFeatureProvider, times(1)).hidden(any(), anyInt());
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index 29e37e4938a8..97e6d5051fd2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -19,7 +19,6 @@ import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static com.google.common.truth.Truth.assertThat;
-import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
@@ -96,7 +95,6 @@ public class LifecycleTest {
OnOptionsItemSelected {
boolean mOnAttachObserved;
- boolean mOnAttachHasContext;
boolean mOnStartObserved;
boolean mOnResumeObserved;
boolean mOnPauseObserved;
@@ -107,9 +105,8 @@ public class LifecycleTest {
boolean mOnOptionsItemSelectedObserved;
@Override
- public void onAttach(Context context) {
+ public void onAttach() {
mOnAttachObserved = true;
- mOnAttachHasContext = context != null;
}
@Override
@@ -194,7 +191,6 @@ public class LifecycleTest {
assertThat(fragment.mFragObserver.mOnOptionsItemSelectedObserved).isTrue();
assertThat(fragment.mFragObserver.mOnAttachObserved).isTrue();
- assertThat(fragment.mFragObserver.mOnAttachHasContext).isTrue();
assertThat(fragment.mFragObserver.mOnStartObserved).isTrue();
assertThat(fragment.mFragObserver.mOnResumeObserved).isTrue();
fragment.onPause();
@@ -218,7 +214,6 @@ public class LifecycleTest {
assertThat(fragment.mFragObserver.mOnOptionsItemSelectedObserved).isTrue();
assertThat(fragment.mFragObserver.mOnAttachObserved).isTrue();
- assertThat(fragment.mFragObserver.mOnAttachHasContext).isTrue();
assertThat(fragment.mFragObserver.mOnStartObserved).isTrue();
assertThat(fragment.mFragObserver.mOnResumeObserved).isTrue();
fragment.onPause();
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml
new file mode 100644
index 000000000000..1947f58f8f5e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12,3c-4.97,0 -9,4.03 -9,9c0,1.39 0.32,2.69 0.88,3.86l1.53,-1.53C5.15,13.6 5,12.82 5,12c0,-3.86 3.14,-7 7,-7s7,3.14 7,7s-3.14,7 -7,7c-0.83,0 -1.62,-0.15 -2.35,-0.42l-1.53,1.53C9.3,20.67 10.61,21 12,21c4.97,0 9,-4.03 9,-9C21,7.03 16.97,3 12,3z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M12.99,15.99l2,0l0,-7l-7,0l0,2l3.59,0l-8.79,8.8l1.41,1.41l8.79,-8.79z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 87de9d4d3b51..964a59170d35 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -220,6 +220,58 @@ asked for it -->
android:orientation="vertical">
<com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/bubble"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:layout_marginBottom="@dimen/notification_importance_button_separation"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_guts_priority_button_bg"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center"
+ >
+ <ImageView
+ android:id="@+id/bubble_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_create_bubble"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/bubble_label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_bubble_title"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/bubble_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_bubble"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
android:id="@+id/alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 008294980d94..19daa9039f55 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1717,12 +1717,18 @@
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_alert_title">Alerting</string>
+ <!-- [CHAR LIMIT=100] Notification Importance title -->
+ <string name="notification_bubble_title">Bubble</string>
+
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
<string name="notification_channel_summary_low">Helps you focus without sound or vibration.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary -->
<string name="notification_channel_summary_default">Gets your attention with sound or vibration.</string>
+ <!-- [CHAR LIMIT=150] Notification Importance title: bubble level summary -->
+ <string name="notification_channel_summary_bubble">Keeps your attention with a floating shortcut to this content.</string>
+
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b9fe9334d14c..91b22d178b9f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -46,6 +46,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
@@ -617,6 +618,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
+ // Force a garbage collection in an attempt to erase any lockscreen password left in
+ // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
+ // dismiss animation janky.
+ ThreadUtils.postOnBackgroundThread(() -> {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException ignored) { }
+ Runtime.getRuntime().gc();
+ });
} else {
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 91ee1b91fd9e..1a0690c1a273 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -75,10 +75,10 @@ import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -125,6 +125,7 @@ import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.wm.DisplayWindowController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -332,6 +333,7 @@ public class Dependency {
@Inject Lazy<CommandQueue> mCommandQueue;
@Inject Lazy<Recents> mRecents;
@Inject Lazy<StatusBar> mStatusBar;
+ @Inject Lazy<DisplayWindowController> mDisplayWindowController;
@Inject
public Dependency() {
@@ -523,6 +525,7 @@ public class Dependency {
mProviders.put(CommandQueue.class, mCommandQueue::get);
mProviders.put(Recents.class, mRecents::get);
mProviders.put(StatusBar.class, mStatusBar::get);
+ mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 385de4acfea8..15a5c2773f0b 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -139,8 +139,7 @@ public class ForegroundServiceController {
// Update appOp if there's an associated pending or visible notification:
final String foregroundKey = getStandardLayoutKey(userId, packageName);
if (foregroundKey != null) {
- final NotificationEntry entry = mEntryManager.getPendingOrCurrentNotif(
- foregroundKey);
+ final NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(foregroundKey);
if (entry != null
&& uid == entry.getSbn().getUid()
&& packageName.equals(entry.getSbn().getPackageName())) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index aab4041aba5f..4b28e4af7d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -141,7 +141,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
public void startServicesIfNeeded() {
String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
- startServicesIfNeeded(names);
+ startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
/**
@@ -153,10 +153,10 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
void startSecondaryUserServicesIfNeeded() {
String[] names =
getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
- startServicesIfNeeded(names);
+ startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
}
- private void startServicesIfNeeded(String[] services) {
+ private void startServicesIfNeeded(String metricsPrefix, String[] services) {
if (mServicesStarted) {
return;
}
@@ -177,12 +177,12 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
Process.myUserHandle().getIdentifier() + ".");
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
- log.traceBegin("StartServices");
+ log.traceBegin(metricsPrefix);
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
if (DEBUG) Log.d(TAG, "loading: " + clsName);
- log.traceBegin("StartServices" + clsName);
+ log.traceBegin(metricsPrefix + clsName);
long ti = System.currentTimeMillis();
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 4516996345b9..170c25a82101 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -71,7 +71,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
private final Runnable mHideHandles = this::hideHandles;
private final Runnable mShowAndGo = this::showAndGoInternal;
private final Provider<AssistHandleViewController> mAssistHandleViewController;
- private final PhenotypeHelper mPhenotypeHelper;
+ private final DeviceConfigHelper mDeviceConfigHelper;
private final Map<AssistHandleBehavior, BehaviorController> mBehaviorMap;
private boolean mHandlesShowing = false;
@@ -90,7 +90,7 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
AssistUtils assistUtils,
@Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
Provider<AssistHandleViewController> assistHandleViewController,
- PhenotypeHelper phenotypeHelper,
+ DeviceConfigHelper deviceConfigHelper,
Map<AssistHandleBehavior, BehaviorController> behaviorMap,
NavigationModeController navigationModeController,
DumpController dumpController) {
@@ -98,14 +98,14 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
mAssistUtils = assistUtils;
mHandler = handler;
mAssistHandleViewController = assistHandleViewController;
- mPhenotypeHelper = phenotypeHelper;
+ mDeviceConfigHelper = deviceConfigHelper;
mBehaviorMap = behaviorMap;
mInGesturalMode = QuickStepContract.isGesturalMode(
navigationModeController.addListener(this::handleNavigationModeChange));
setBehavior(getBehaviorMode());
- mPhenotypeHelper.addOnPropertiesChangedListener(
+ mDeviceConfigHelper.addOnPropertiesChangedListener(
mHandler::post,
(properties) -> {
if (properties.getKeyset().contains(
@@ -205,19 +205,19 @@ public final class AssistHandleBehaviorController implements AssistHandleCallbac
}
private long getShownFrequencyThreshold() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS,
DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS);
}
private long getShowAndGoDuration() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS,
DEFAULT_SHOW_AND_GO_DURATION_MS);
}
private String getBehaviorMode() {
- return mPhenotypeHelper.getString(
+ return mDeviceConfigHelper.getString(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE,
DEFAULT_BEHAVIOR.toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 46ae84a95fad..9793d727f038 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -155,7 +155,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
private final Clock mClock;
private final Handler mHandler;
- private final PhenotypeHelper mPhenotypeHelper;
+ private final DeviceConfigHelper mDeviceConfigHelper;
private final Lazy<StatusBarStateController> mStatusBarStateController;
private final Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
private final Lazy<OverviewProxyService> mOverviewProxyService;
@@ -189,7 +189,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
AssistHandleReminderExpBehavior(
@Named(UPTIME_NAME) Clock clock,
@Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
- PhenotypeHelper phenotypeHelper,
+ DeviceConfigHelper deviceConfigHelper,
Lazy<StatusBarStateController> statusBarStateController,
Lazy<ActivityManagerWrapper> activityManagerWrapper,
Lazy<OverviewProxyService> overviewProxyService,
@@ -199,7 +199,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
Lazy<BroadcastDispatcher> broadcastDispatcher) {
mClock = clock;
mHandler = handler;
- mPhenotypeHelper = phenotypeHelper;
+ mDeviceConfigHelper = deviceConfigHelper;
mStatusBarStateController = statusBarStateController;
mActivityManagerWrapper = activityManagerWrapper;
mOverviewProxyService = overviewProxyService;
@@ -465,55 +465,55 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
}
private long getLearningTimeMs() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS,
DEFAULT_LEARNING_TIME_MS);
}
private int getLearningCount() {
- return mPhenotypeHelper.getInt(
+ return mDeviceConfigHelper.getInt(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT,
DEFAULT_LEARNING_COUNT);
}
private long getShowAndGoDelayedShortDelayMs() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS,
DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS);
}
private long getShowAndGoDelayedLongDelayMs() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_LONG_DELAY_MS,
DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS);
}
private long getShowAndGoDelayResetTimeoutMs() {
- return mPhenotypeHelper.getLong(
+ return mDeviceConfigHelper.getLong(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS,
DEFAULT_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS);
}
private boolean getSuppressOnLockscreen() {
- return mPhenotypeHelper.getBoolean(
+ return mDeviceConfigHelper.getBoolean(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LOCKSCREEN,
DEFAULT_SUPPRESS_ON_LOCKSCREEN);
}
private boolean getSuppressOnLauncher() {
- return mPhenotypeHelper.getBoolean(
+ return mDeviceConfigHelper.getBoolean(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LAUNCHER,
DEFAULT_SUPPRESS_ON_LAUNCHER);
}
private boolean getSuppressOnApps() {
- return mPhenotypeHelper.getBoolean(
+ return mDeviceConfigHelper.getBoolean(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_APPS,
DEFAULT_SUPPRESS_ON_APPS);
}
private boolean getShowWhenTaught() {
- return mPhenotypeHelper.getBoolean(
+ return mDeviceConfigHelper.getBoolean(
SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT,
DEFAULT_SHOW_WHEN_TAUGHT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java b/packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java
index 05a01dd48641..86b7c748ea77 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java
@@ -28,15 +28,15 @@ import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * Wrapper class for retrieving phenotype flag values.
+ * Wrapper class for retrieving System UI device configuration values.
*
* Can be mocked in tests for ease of testing the effects of particular values.
*/
@Singleton
-public class PhenotypeHelper {
+public class DeviceConfigHelper {
@Inject
- public PhenotypeHelper() {}
+ public DeviceConfigHelper() {}
public long getLong(String name, long defaultValue) {
return whitelistIpcs(() ->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 9f7bdd43fb11..1052a991dff8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -78,7 +78,6 @@ import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -352,14 +351,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* @param userId the id of the user
*/
private void restoreBubbles(@UserIdInt int userId) {
- NotificationData notificationData =
- mNotificationEntryManager.getNotificationData();
ArraySet<String> savedBubbleKeys = mSavedBubbleKeysPerUser.get(userId);
if (savedBubbleKeys == null) {
// There were no bubbles saved for this used.
return;
}
- for (NotificationEntry e : notificationData.getNotificationsForCurrentUser()) {
+ for (NotificationEntry e :
+ mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
if (savedBubbleKeys.contains(e.getKey())
&& mNotificationInterruptionStateProvider.shouldBubbleUp(e)
&& canLaunchInActivityView(mContext, e)) {
@@ -458,7 +456,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
public boolean isBubbleNotificationSuppressedFromShade(String key) {
boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
&& !mBubbleData.getBubbleWithKey(key).showInShadeWhenBubble();
- NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry = mNotificationEntryManager.getActiveNotificationUnfiltered(key);
String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey));
@@ -571,7 +569,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
new NotificationRemoveInterceptor() {
@Override
public boolean onNotificationRemoveRequested(String key, int reason) {
- NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry =
+ mNotificationEntryManager.getActiveNotificationUnfiltered(key);
String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
@@ -768,7 +767,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
String notifKey = mBubbleData.getSummaryKey(groupKey);
mBubbleData.removeSuppressedSummary(groupKey);
NotificationEntry entry =
- mNotificationEntryManager.getNotificationData().get(notifKey);
+ mNotificationEntryManager.getActiveNotificationUnfiltered(notifKey);
mNotificationEntryManager.performRemoveNotification(
entry.getSbn(), UNDEFINED_DISMISS_REASON);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index f4d48b2a71a7..2ca993bd200a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -184,8 +184,9 @@ public class BubbleData {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "notificationEntryUpdated: " + entry);
}
+
Bubble bubble = getBubbleWithKey(entry.getKey());
- suppressFlyout = !entry.getRanking().visuallyInterruptive() || suppressFlyout;
+ suppressFlyout |= !shouldShowFlyout(entry);
if (bubble == null) {
// Create a new bubble
@@ -298,6 +299,15 @@ public class BubbleData {
return bubbleChildren;
}
+ private boolean shouldShowFlyout(NotificationEntry notif) {
+ if (notif.getRanking().visuallyInterruptive()) {
+ return true;
+ }
+ final boolean suppressedFromShade = hasBubbleWithKey(notif.getKey())
+ && !getBubbleWithKey(notif.getKey()).showInShadeWhenBubble();
+ return suppressedFromShade;
+ }
+
private void doAdd(Bubble bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "doAdd: " + bubble);
@@ -510,7 +520,7 @@ public class BubbleData {
* required to keep grouping intact.
*
* @param minPosition the first insert point to consider
- * @param newBubble the bubble to insert
+ * @param newBubble the bubble to insert
* @return the position where the bubble was inserted
*/
private int insertBubble(int minPosition, Bubble newBubble) {
@@ -683,15 +693,19 @@ public class BubbleData {
* Description of current bubble data state.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print("selected: "); pw.println(mSelectedBubble != null
+ pw.print("selected: ");
+ pw.println(mSelectedBubble != null
? mSelectedBubble.getKey()
: "null");
- pw.print("expanded: "); pw.println(mExpanded);
- pw.print("count: "); pw.println(mBubbles.size());
+ pw.print("expanded: ");
+ pw.println(mExpanded);
+ pw.print("count: ");
+ pw.println(mBubbles.size());
for (Bubble bubble : mBubbles) {
bubble.dump(fd, pw, args);
}
- pw.print("summaryKeys: "); pw.println(mSuppressedGroupKeys.size());
+ pw.print("summaryKeys: ");
+ pw.println(mSuppressedGroupKeys.size());
for (String key : mSuppressedGroupKeys.keySet()) {
pw.println(" suppressing: " + key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 6744d74004f0..7007f9defee6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.DozeServiceHost;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -50,6 +51,7 @@ import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotControllerImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -257,4 +259,7 @@ public abstract class DependencyBinder {
@Binds
public abstract VolumeComponent provideVolumeComponent(
VolumeDialogComponent volumeDialogComponent);
+ /** */
+ @Binds
+ public abstract HeadsUpManager bindHeadsUpManager(HeadsUpManagerPhone headsUpManagerPhone);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 48c72d311b1c..f1d02bb61ef9 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -33,7 +33,7 @@ import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -74,7 +74,7 @@ abstract class SystemUIDefaultModule {
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment(
+ abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
KeyguardEnvironmentImpl keyguardEnvironment);
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index d332f59a4500..52390823a72c 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -53,6 +53,11 @@ public interface DockManager {
*/
boolean isDocked();
+ /**
+ * Returns true if it is hiding docking UI.
+ */
+ boolean isHidden();
+
/** Callback for receiving dock events */
interface DockEventListener {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java b/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
index fa7f5032ca16..f77091028527 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
@@ -38,4 +38,9 @@ public class DockManagerImpl implements DockManager {
public boolean isDocked() {
return false;
}
+
+ @Override
+ public boolean isHidden() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 419fd622d1df..c16dce12041d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -16,9 +16,7 @@
package com.android.systemui.doze;
-import android.content.Context;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
@@ -35,23 +33,19 @@ public class DozeDockHandler implements DozeMachine.Part {
private static final String TAG = "DozeDockHandler";
private static final boolean DEBUG = DozeService.DEBUG;
- private final DozeMachine mMachine;
- private final DozeHost mDozeHost;
private final AmbientDisplayConfiguration mConfig;
- private final Handler mHandler;
- private final DockEventListener mDockEventListener = new DockEventListener();
+ private final DozeMachine mMachine;
private final DockManager mDockManager;
+ private final DockEventListener mDockEventListener;
private int mDockState = DockManager.STATE_NONE;
- private boolean mPulsePending;
- public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
- AmbientDisplayConfiguration config, Handler handler, DockManager dockManager) {
+ public DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine,
+ DockManager dockManager) {
mMachine = machine;
- mDozeHost = dozeHost;
mConfig = config;
- mHandler = handler;
mDockManager = dockManager;
+ mDockEventListener = new DockEventListener();
}
@Override
@@ -60,18 +54,6 @@ public class DozeDockHandler implements DozeMachine.Part {
case INITIALIZED:
mDockEventListener.register();
break;
- case DOZE_AOD:
- if (mDockState == DockManager.STATE_DOCKED_HIDE) {
- mMachine.requestState(State.DOZE);
- break;
- }
- // continue below
- case DOZE:
- if (mDockState == DockManager.STATE_DOCKED && !mPulsePending) {
- mPulsePending = true;
- mHandler.post(() -> requestPulse(newState));
- }
- break;
case FINISH:
mDockEventListener.unregister();
break;
@@ -80,64 +62,36 @@ public class DozeDockHandler implements DozeMachine.Part {
}
}
- private void requestPulse(State dozeState) {
- if (!mDozeHost.isPulsingBlocked() && dozeState.canPulse()) {
- mMachine.requestPulse(DozeEvent.PULSE_REASON_DOCKING);
- }
- mPulsePending = false;
- }
-
- private void requestPulseOutNow(State dozeState) {
- if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING
- || dozeState == State.DOZE_PULSING_BRIGHT) {
- final int pulseReason = mMachine.getPulseReason();
- if (pulseReason == DozeEvent.PULSE_REASON_DOCKING) {
- mDozeHost.stopPulsing();
- }
- }
- }
-
- private boolean isDocked() {
- return mDockState == DockManager.STATE_DOCKED
- || mDockState == DockManager.STATE_DOCKED_HIDE;
- }
-
@Override
public void dump(PrintWriter pw) {
- pw.print(" DozeDockTriggers docking="); pw.println(isDocked());
+ pw.println("DozeDockHandler:");
+ pw.println(" dockState=" + mDockState);
}
private class DockEventListener implements DockManager.DockEventListener {
private boolean mRegistered;
@Override
- public void onEvent(int event) {
- if (DEBUG) Log.d(TAG, "dock event = " + event);
- final DozeMachine.State dozeState = mMachine.getState();
- mDockState = event;
+ public void onEvent(int dockState) {
+ if (DEBUG) Log.d(TAG, "dock event = " + dockState);
+ final DozeMachine.State nextState;
+ mDockState = dockState;
switch (mDockState) {
case DockManager.STATE_DOCKED:
- requestPulse(dozeState);
+ nextState = State.DOZE_AOD_DOCKED;
break;
case DockManager.STATE_NONE:
- if (dozeState == State.DOZE
- && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
- mMachine.requestState(State.DOZE_AOD);
- }
- else {
- requestPulseOutNow(dozeState);
- }
+ nextState = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) ? State.DOZE_AOD
+ : State.DOZE;
break;
case DockManager.STATE_DOCKED_HIDE:
- if (dozeState == State.DOZE_AOD) {
- mMachine.requestState(State.DOZE);
- } else {
- requestPulseOutNow(dozeState);
- }
+ nextState = State.DOZE;
break;
default:
- // no-op
+ return;
}
+
+ mMachine.requestState(nextState);
}
void register() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 71e1593302c3..43db85bd91ec 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -102,7 +102,7 @@ public class DozeFactory {
wrappedService, mDozeParameters);
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
- mWakefulnessLifecycle, mBatteryController, mDozeLog);
+ mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager);
machine.setParts(new DozeMachine.Part[]{
new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
new DozeFalsingManagerAdapter(mFalsingManager),
@@ -117,8 +117,7 @@ public class DozeFactory {
mDozeServiceHost, mDozeParameters, mHandler),
new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
mDozeParameters),
- new DozeDockHandler(dozeService, machine, mDozeServiceHost, config, mHandler,
- mDockManager),
+ new DozeDockHandler(config, machine, mDockManager),
new DozeAuthRemover(dozeService)
});
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 75b1d6c87800..40603ab24c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -24,6 +24,7 @@ import android.util.Log;
import android.view.Display;
import com.android.internal.util.Preconditions;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -72,7 +73,9 @@ public class DozeMachine {
/** AOD, but the display is temporarily off. */
DOZE_AOD_PAUSED,
/** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
- DOZE_AOD_PAUSING;
+ DOZE_AOD_PAUSING,
+ /** Always-on doze. Device is awake, showing docking UI and listening for pulse triggers. */
+ DOZE_AOD_DOCKED;
boolean canPulse() {
switch (this) {
@@ -80,6 +83,7 @@ public class DozeMachine {
case DOZE_AOD:
case DOZE_AOD_PAUSED:
case DOZE_AOD_PAUSING:
+ case DOZE_AOD_DOCKED:
return true;
default:
return false;
@@ -91,6 +95,7 @@ public class DozeMachine {
case DOZE_REQUEST_PULSE:
case DOZE_PULSING:
case DOZE_PULSING_BRIGHT:
+ case DOZE_AOD_DOCKED:
return true;
default:
return false;
@@ -109,6 +114,7 @@ public class DozeMachine {
return Display.STATE_OFF;
case DOZE_PULSING:
case DOZE_PULSING_BRIGHT:
+ case DOZE_AOD_DOCKED:
return Display.STATE_ON;
case DOZE_AOD:
case DOZE_AOD_PAUSING:
@@ -130,16 +136,18 @@ public class DozeMachine {
private State mState = State.UNINITIALIZED;
private int mPulseReason;
private boolean mWakeLockHeldForCurrentState = false;
+ private DockManager mDockManager;
- public DozeMachine(Service service, AmbientDisplayConfiguration config,
- WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
- BatteryController batteryController, DozeLog dozeLog) {
+ public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock,
+ WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController,
+ DozeLog dozeLog, DockManager dockManager) {
mDozeService = service;
mConfig = config;
mWakefulnessLifecycle = wakefulnessLifecycle;
mWakeLock = wakeLock;
mBatteryController = batteryController;
mDozeLog = dozeLog;
+ mDockManager = dockManager;
}
/** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
@@ -352,6 +360,8 @@ public class DozeMachine {
if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE
|| wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) {
nextState = State.FINISH;
+ } else if (mDockManager.isDocked()) {
+ nextState = mDockManager.isHidden() ? State.DOZE : State.DOZE_AOD_DOCKED;
} else if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
nextState = State.DOZE_AOD;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 39a256248aae..c9faf69cfd6f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -113,6 +113,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
break;
case DOZE_AOD:
case DOZE_REQUEST_PULSE:
+ case DOZE_AOD_DOCKED:
setLightSensorEnabled(true);
break;
case DOZE:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index e1b4f3122861..3abeea91cdee 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
@@ -89,10 +90,10 @@ public class DozeScreenState implements DozeMachine.Part {
}
final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
- final boolean pulseEnding = oldState == DOZE_PULSE_DONE && newState == DOZE_AOD;
- final boolean turningOn = (oldState == DOZE_AOD_PAUSED
- || oldState == DOZE) && newState == DOZE_AOD;
- final boolean turningOff = (oldState == DOZE_AOD && newState == DOZE)
+ final boolean pulseEnding = oldState == DOZE_PULSE_DONE && isAlwaysOnState(newState);
+ final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE)
+ && isAlwaysOnState(newState);
+ final boolean turningOff = (isAlwaysOnState(oldState) && newState == DOZE)
|| (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED);
final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
if (messagePending || justInitialized || pulseEnding || turningOn) {
@@ -131,6 +132,10 @@ public class DozeScreenState implements DozeMachine.Part {
}
}
+ private boolean isAlwaysOnState(DozeMachine.State state) {
+ return state == DOZE_AOD || state == DOZE_AOD_DOCKED;
+ }
+
private void applyPendingScreenState() {
applyScreenState(mPendingScreenState);
mPendingScreenState = Display.STATE_UNKNOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1134268aa5c6..2d6b946fc67e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -304,9 +304,7 @@ public class DozeTriggers implements DozeMachine.Part {
case INITIALIZED:
mBroadcastReceiver.register(mBroadcastDispatcher);
mDozeHost.addCallback(mHostCallback);
- if (mDockManager != null) {
- mDockManager.addListener(mDockEventListener);
- }
+ mDockManager.addListener(mDockEventListener);
mDozeSensors.requestTemporaryDisable();
checkTriggersAtInit();
break;
@@ -326,6 +324,7 @@ public class DozeTriggers implements DozeMachine.Part {
break;
case DOZE_PULSING:
case DOZE_PULSING_BRIGHT:
+ case DOZE_AOD_DOCKED:
mDozeSensors.setTouchscreenSensorsListening(false);
mDozeSensors.setProxListening(true);
mDozeSensors.setPaused(false);
@@ -339,9 +338,7 @@ public class DozeTriggers implements DozeMachine.Part {
case FINISH:
mBroadcastReceiver.unregister(mBroadcastDispatcher);
mDozeHost.removeCallback(mHostCallback);
- if (mDockManager != null) {
- mDockManager.removeListener(mDockEventListener);
- }
+ mDockManager.removeListener(mDockEventListener);
mDozeSensors.setListening(false);
mDozeSensors.setProxListening(false);
break;
@@ -399,7 +396,8 @@ public class DozeTriggers implements DozeMachine.Part {
private boolean canPulse() {
return mMachine.getState() == DozeMachine.State.DOZE
- || mMachine.getState() == DozeMachine.State.DOZE_AOD;
+ || mMachine.getState() == DozeMachine.State.DOZE_AOD
+ || mMachine.getState() == DozeMachine.State.DOZE_AOD_DOCKED;
}
private void continuePulseRequest(int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index f1557838fd73..a6aa90916c25 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -121,6 +121,7 @@ public class DozeUi implements DozeMachine.Part {
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD:
+ case DOZE_AOD_DOCKED:
if (oldState == DOZE_AOD_PAUSED || oldState == DOZE) {
// Whenever turning on the display, it's necessary to push a new frame.
// The display buffers will be empty and need to be filled.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 9457dc9e580b..7f1b35678867 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -54,6 +54,7 @@ public class DozeWallpaperState implements DozeMachine.Part {
switch (newState) {
case DOZE:
case DOZE_AOD:
+ case DOZE_AOD_DOCKED:
case DOZE_AOD_PAUSING:
case DOZE_AOD_PAUSED:
case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index bb2d142c11a1..51c2ddca869c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -52,6 +52,7 @@ import android.os.Vibrator;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
+import android.sysprop.TelephonyProperties;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -81,7 +82,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.util.ScreenRecordHelper;
import com.android.internal.util.ScreenshotHelper;
@@ -310,8 +310,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
R.string.global_actions_airplane_mode_off_status) {
void onToggle(boolean on) {
- if (mHasTelephony && Boolean.parseBoolean(
- SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+ if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
mIsWaitingForEcmExit = true;
// Launch ECM exit dialog
Intent ecmDialogIntent =
@@ -328,8 +327,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
if (!mHasTelephony) return;
// In ECM mode airplane state cannot be changed
- if (!(Boolean.parseBoolean(
- SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+ if (!TelephonyProperties.in_ecm_mode().orElse(false)) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 0134aa3a15df..5de6d1c42b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -169,7 +169,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) {
v.setText(mContext.getString(
com.android.internal.R.string.bugreport_status,
- Build.VERSION.RELEASE,
+ Build.VERSION.RELEASE_OR_CODENAME,
Build.ID));
v.setVisibility(View.VISIBLE);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 694964075032..1a4c327b4405 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -47,7 +47,9 @@ import android.widget.TextView;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
@@ -61,10 +63,13 @@ public class QSMediaPlayer {
private Context mContext;
private LinearLayout mMediaNotifView;
+ private View mSeamless;
private MediaSession.Token mToken;
private MediaController mController;
private int mWidth;
private int mHeight;
+ private int mForegroundColor;
+ private int mBackgroundColor;
/**
*
@@ -93,15 +98,17 @@ public class QSMediaPlayer {
* @param iconColor foreground color (for text, icons)
* @param bgColor background color
* @param actionsContainer a LinearLayout containing the media action buttons
- * @param notif
+ * @param notif reference to original notification
+ * @param device current playback device
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
- View actionsContainer, Notification notif) {
+ View actionsContainer, Notification notif, MediaDevice device) {
Log.d(TAG, "got media session: " + token);
mToken = token;
+ mForegroundColor = iconColor;
+ mBackgroundColor = bgColor;
mController = new MediaController(mContext, token);
MediaMetadata mMediaMetadata = mController.getMetadata();
-
if (mMediaMetadata == null) {
Log.e(TAG, "Media metadata was null");
return;
@@ -123,9 +130,6 @@ public class QSMediaPlayer {
headerView.removeAllViews();
headerView.addView(result);
- View seamless = headerView.findViewById(com.android.internal.R.id.media_seamless);
- seamless.setVisibility(View.VISIBLE);
-
// App icon
ImageView appIcon = headerView.findViewById(com.android.internal.R.id.icon);
Drawable iconDrawable = icon.loadDrawable(mContext);
@@ -168,23 +172,11 @@ public class QSMediaPlayer {
}
// Transfer chip
- View transferBackgroundView = headerView.findViewById(
- com.android.internal.R.id.media_seamless);
- LinearLayout viewLayout = (LinearLayout) transferBackgroundView;
- RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
- GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
- rect.setStroke(2, iconColor);
- rect.setColor(bgColor);
- ImageView transferIcon = headerView.findViewById(
- com.android.internal.R.id.media_seamless_image);
- transferIcon.setBackgroundColor(bgColor);
- transferIcon.setImageTintList(ColorStateList.valueOf(iconColor));
- TextView transferText = headerView.findViewById(
- com.android.internal.R.id.media_seamless_text);
- transferText.setTextColor(iconColor);
-
+ mSeamless = headerView.findViewById(com.android.internal.R.id.media_seamless);
+ mSeamless.setVisibility(View.VISIBLE);
+ updateChip(device);
ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
- transferBackgroundView.setOnClickListener(v -> {
+ mSeamless.setOnClickListener(v -> {
final Intent intent = new Intent()
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
mActivityStarter.startActivity(intent, false, true /* dismissShade */,
@@ -219,10 +211,13 @@ public class QSMediaPlayer {
com.android.internal.R.id.action3,
com.android.internal.R.id.action4
};
- for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
+
+ int i = 0;
+ for (; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
- if (thatBtn == null || thatBtn.getDrawable() == null) {
+ if (thatBtn == null || thatBtn.getDrawable() == null
+ || thatBtn.getVisibility() != View.VISIBLE) {
thisBtn.setVisibility(View.GONE);
continue;
}
@@ -235,6 +230,13 @@ public class QSMediaPlayer {
thatBtn.performClick();
});
}
+
+ // Hide any unused buttons
+ for (; i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ thisBtn.setVisibility(View.GONE);
+ Log.d(TAG, "hid a button");
+ }
}
public MediaSession.Token getMediaSessionToken() {
@@ -284,6 +286,7 @@ public class QSMediaPlayer {
mMediaNotifView.setBackground(roundedDrawable);
} else {
Log.e(TAG, "No album art available");
+ mMediaNotifView.setBackground(null);
}
}
@@ -303,4 +306,41 @@ public class QSMediaPlayer {
return cropped;
}
+
+ protected void updateChip(MediaDevice device) {
+ if (mSeamless == null) {
+ return;
+ }
+ ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor);
+
+ // Update the outline color
+ LinearLayout viewLayout = (LinearLayout) mSeamless;
+ RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
+ GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
+ rect.setStroke(2, mForegroundColor);
+ rect.setColor(mBackgroundColor);
+
+ ImageView iconView = mSeamless.findViewById(com.android.internal.R.id.media_seamless_image);
+ TextView deviceName = mSeamless.findViewById(com.android.internal.R.id.media_seamless_text);
+ deviceName.setTextColor(fgTintList);
+
+ if (device != null) {
+ Drawable icon = device.getIcon();
+ iconView.setVisibility(View.VISIBLE);
+ iconView.setImageTintList(fgTintList);
+
+ if (icon instanceof AdaptiveIcon) {
+ AdaptiveIcon aIcon = (AdaptiveIcon) icon;
+ aIcon.setBackgroundColor(mBackgroundColor);
+ iconView.setImageDrawable(aIcon);
+ } else {
+ iconView.setImageDrawable(icon);
+ }
+ deviceName.setText(device.getName());
+ } else {
+ // Reset to default
+ iconView.setVisibility(View.GONE);
+ deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index cac90257cd43..5e98f9356403 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -46,6 +46,8 @@ import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
import com.android.systemui.Dependency;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
@@ -70,6 +72,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
@@ -92,6 +95,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final LinearLayout mMediaCarousel;
private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
+ private LocalMediaManager mLocalMediaManager;
+ private MediaDevice mDevice;
protected boolean mExpanded;
protected boolean mListening;
@@ -117,6 +122,31 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final PluginManager mPluginManager;
private NPVPluginManager mNPVPluginManager;
+ private final LocalMediaManager.DeviceCallback mDeviceCallback =
+ new LocalMediaManager.DeviceCallback() {
+ @Override
+ public void onDeviceListUpdate(List<MediaDevice> devices) {
+ MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ // Check because this can be called several times while changing devices
+ if (mDevice == null || !mDevice.equals(currentDevice)) {
+ mDevice = currentDevice;
+ for (QSMediaPlayer p : mMediaPlayers) {
+ p.updateChip(mDevice);
+ }
+ }
+ }
+
+ @Override
+ public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
+ if (mDevice == null || !mDevice.equals(device)) {
+ mDevice = device;
+ for (QSMediaPlayer p : mMediaPlayers) {
+ p.updateChip(mDevice);
+ }
+ }
+ }
+ };
+
public QSPanel(Context context) {
this(context, null);
}
@@ -208,6 +238,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
Log.e(TAG, "Tried to add media session without player!");
return;
}
+ if (token == null) {
+ Log.e(TAG, "Media session token was null!");
+ return;
+ }
+
QSMediaPlayer player = null;
String packageName = notif.getPackageName();
for (QSMediaPlayer p : mMediaPlayers) {
@@ -250,10 +285,17 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
Log.d(TAG, "setting player session");
player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
- notif.getNotification());
+ notif.getNotification(), mDevice);
if (mMediaPlayers.size() > 0) {
((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
+
+ // Set up listener for device changes
+ // TODO: integrate with MediaTransferManager?
+ mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+ mLocalMediaManager.startScan();
+ mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ mLocalMediaManager.registerCallback(mDeviceCallback);
}
}
@@ -326,6 +368,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mBrightnessMirrorController.removeCallback(this);
}
if (mDumpController != null) mDumpController.unregisterDumpable(this);
+ if (mLocalMediaManager != null) {
+ mLocalMediaManager.stopScan();
+ mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ }
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index 3ec71ac30da1..d7b8b83f01fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -76,9 +76,11 @@ public class QuickQSMediaPlayer {
* @param iconColor foreground color (for text, icons)
* @param bgColor background color
* @param actionsContainer a LinearLayout containing the media action buttons
+ * @param actionsToShow indices of which actions to display in the mini player
+ * (max 3: Notification.MediaStyle.MAX_MEDIA_BUTTONS_IN_COMPACT)
*/
public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
- View actionsContainer) {
+ View actionsContainer, int[] actionsToShow) {
Log.d(TAG, "Setting media session: " + token);
mToken = token;
mController = new MediaController(mContext, token);
@@ -110,32 +112,46 @@ public class QuickQSMediaPlayer {
titleText.setText(songName);
titleText.setTextColor(iconColor);
- // Action buttons
- LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
+ // Buttons we can display
final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
- // TODO some apps choose different buttons to show in compact mode
+ // Existing buttons in the notification
+ LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
final int[] notifActionIds = {
+ com.android.internal.R.id.action0,
com.android.internal.R.id.action1,
com.android.internal.R.id.action2,
- com.android.internal.R.id.action3
+ com.android.internal.R.id.action3,
+ com.android.internal.R.id.action4
};
- for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
- ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
- ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
- if (thatBtn == null || thatBtn.getDrawable() == null) {
- thisBtn.setVisibility(View.GONE);
- continue;
- }
- Drawable thatIcon = thatBtn.getDrawable();
- thisBtn.setImageDrawable(thatIcon.mutate());
- thisBtn.setVisibility(View.VISIBLE);
+ int i = 0;
+ if (actionsToShow != null) {
+ int maxButtons = Math.min(actionsToShow.length, parentActionsLayout.getChildCount());
+ maxButtons = Math.min(maxButtons, actionIds.length);
+ for (; i < maxButtons; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ int thatId = notifActionIds[actionsToShow[i]];
+ ImageButton thatBtn = parentActionsLayout.findViewById(thatId);
+ if (thatBtn == null || thatBtn.getDrawable() == null
+ || thatBtn.getVisibility() != View.VISIBLE) {
+ thisBtn.setVisibility(View.GONE);
+ continue;
+ }
+
+ Drawable thatIcon = thatBtn.getDrawable();
+ thisBtn.setImageDrawable(thatIcon.mutate());
+ thisBtn.setVisibility(View.VISIBLE);
+ thisBtn.setOnClickListener(v -> {
+ thatBtn.performClick();
+ });
+ }
+ }
- thisBtn.setOnClickListener(v -> {
- Log.d(TAG, "clicking on other button");
- thatBtn.performClick();
- });
+ // Hide any unused buttons
+ for (; i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ thisBtn.setVisibility(View.GONE);
}
}
@@ -186,6 +202,7 @@ public class QuickQSMediaPlayer {
mMediaNotifView.setBackground(roundedDrawable);
} else {
Log.e(TAG, "No album art available");
+ mMediaNotifView.setBackground(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index da74663191f2..4afcf013507d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,17 +21,16 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.quicksettings.Tile;
+import android.sysprop.TelephonyProperties;
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.ActivityStarter;
@@ -75,8 +74,7 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> {
public void handleClick() {
boolean airplaneModeEnabled = mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !airplaneModeEnabled);
- if (!airplaneModeEnabled && Boolean.parseBoolean(
- SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+ if (!airplaneModeEnabled && TelephonyProperties.in_ecm_mode().orElse(false)) {
mActivityStarter.postStartActivityDismissingKeyguard(
new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
index 926ae71194d9..b21c65ea85ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaTransferManager.java
@@ -19,10 +19,12 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.RippleDrawable;
import android.service.notification.StatusBarNotification;
import android.util.FeatureFlagUtils;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
@@ -30,19 +32,29 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.internal.R;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Class for handling MediaTransfer state over a set of notifications.
*/
public class MediaTransferManager {
private final Context mContext;
private final ActivityStarter mActivityStarter;
+ private MediaDevice mDevice;
+ private List<View> mViews = new ArrayList<>();
+ private LocalMediaManager mLocalMediaManager;
+
+ private static final String TAG = "MediaTransferManager";
private final View.OnClickListener mOnClickHandler = new View.OnClickListener() {
@Override
@@ -70,9 +82,50 @@ public class MediaTransferManager {
}
};
+ private final LocalMediaManager.DeviceCallback mMediaDeviceCallback =
+ new LocalMediaManager.DeviceCallback() {
+ @Override
+ public void onDeviceListUpdate(List<MediaDevice> devices) {
+ MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ // Check because this can be called several times while changing devices
+ if (mDevice == null || !mDevice.equals(currentDevice)) {
+ mDevice = currentDevice;
+ updateAllChips();
+ }
+ }
+
+ @Override
+ public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
+ if (mDevice == null || !mDevice.equals(device)) {
+ mDevice = device;
+ updateAllChips();
+ }
+ }
+ };
+
public MediaTransferManager(Context context) {
mContext = context;
mActivityStarter = Dependency.get(ActivityStarter.class);
+ mLocalMediaManager = new LocalMediaManager(mContext, null, null);
+ }
+
+ /**
+ * Mark a view as removed. If no views remain the media device listener will be unregistered.
+ * @param root
+ */
+ public void setRemoved(View root) {
+ if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
+ || mLocalMediaManager == null || root == null) {
+ return;
+ }
+ View view = root.findViewById(com.android.internal.R.id.media_seamless);
+ if (mViews.remove(view)) {
+ if (mViews.size() == 0) {
+ mLocalMediaManager.unregisterCallback(mMediaDeviceCallback);
+ }
+ } else {
+ Log.e(TAG, "Tried to remove unknown view " + view);
+ }
}
private ExpandableNotificationRow getRowForParent(ViewParent parent) {
@@ -92,7 +145,8 @@ public class MediaTransferManager {
* @param entry The entry of MediaTransfer action button.
*/
public void applyMediaTransferView(ViewGroup root, NotificationEntry entry) {
- if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)) {
+ if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
+ || mLocalMediaManager == null || root == null) {
return;
}
@@ -103,23 +157,59 @@ public class MediaTransferManager {
view.setVisibility(View.VISIBLE);
view.setOnClickListener(mOnClickHandler);
+ if (!mViews.contains(view)) {
+ mViews.add(view);
+ if (mViews.size() == 1) {
+ mLocalMediaManager.registerCallback(mMediaDeviceCallback);
+ }
+ }
+
+ // Initial update
+ mLocalMediaManager.startScan();
+ mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+ updateChip(view);
+ }
+ private void updateAllChips() {
+ for (View view : mViews) {
+ updateChip(view);
+ }
+ }
+
+ private void updateChip(View view) {
ExpandableNotificationRow enr = getRowForParent(view.getParent());
- int color = enr.getNotificationHeader().getOriginalIconColor();
- ColorStateList tintList = ColorStateList.valueOf(color);
+ int fgColor = enr.getNotificationHeader().getOriginalIconColor();
+ ColorStateList fgTintList = ColorStateList.valueOf(fgColor);
+ int bgColor = enr.getCurrentBackgroundTint();
- // Update the outline color
+ // Update outline color
LinearLayout viewLayout = (LinearLayout) view;
RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
- rect.setStroke(2, color);
-
- // Update the image color
- ImageView image = view.findViewById(R.id.media_seamless_image);
- image.setImageTintList(tintList);
-
- // Update the text color
- TextView text = view.findViewById(R.id.media_seamless_text);
- text.setTextColor(tintList);
+ rect.setStroke(2, fgColor);
+ rect.setColor(bgColor);
+
+ ImageView iconView = view.findViewById(com.android.internal.R.id.media_seamless_image);
+ TextView deviceName = view.findViewById(com.android.internal.R.id.media_seamless_text);
+ deviceName.setTextColor(fgTintList);
+
+ if (mDevice != null) {
+ Drawable icon = mDevice.getIcon();
+ iconView.setVisibility(View.VISIBLE);
+ iconView.setImageTintList(fgTintList);
+
+ if (icon instanceof AdaptiveIcon) {
+ AdaptiveIcon aIcon = (AdaptiveIcon) icon;
+ aIcon.setBackgroundColor(bgColor);
+ iconView.setImageDrawable(aIcon);
+ } else {
+ iconView.setImageDrawable(icon);
+ }
+ deviceName.setText(mDevice.getName());
+ } else {
+ // Reset to default
+ iconView.setVisibility(View.GONE);
+ deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index c4de2d3572bd..98a267599f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -110,8 +110,7 @@ public class NotificationListener extends NotificationListenerWithPlugins {
}
String key = sbn.getKey();
- boolean isUpdate =
- mEntryManager.getNotificationData().get(key) != null;
+ boolean isUpdate = mEntryManager.getActiveNotificationUnfiltered(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since` we're not going to show them
// anyway. This is true also when the summary is canceled,
@@ -126,8 +125,7 @@ public class NotificationListener extends NotificationListenerWithPlugins {
if (isUpdate) {
mEntryManager.removeNotification(key, rankingMap, UNDEFINED_DISMISS_REASON);
} else {
- mEntryManager.getNotificationData()
- .updateRanking(rankingMap, "onNotificationPosted");
+ mEntryManager.updateRanking(rankingMap, "onNotificationPosted");
}
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 571d3d7a11be..021e7e15c7f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar;
+import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -126,7 +127,7 @@ public class NotificationLockscreenUserManagerImpl implements
updatePublicMode();
// The filtering needs to happen before the update call below in order to make sure
// the presenter has the updated notifications from the new user
- getEntryManager().getNotificationData().filterAndSort("user switched");
+ getEntryManager().reapplyFilterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
@@ -148,17 +149,17 @@ public class NotificationLockscreenUserManagerImpl implements
}
}
if (notificationKey != null) {
- final int count =
- getEntryManager().getNotificationData().getActiveNotifications().size();
- final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+ NotificationEntry entry =
+ getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+ final int count = getEntryManager().getActiveNotificationsCount();
+ final int rank = entry != null ? entry.getRanking().getRank() : 0;
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(
- getEntryManager().getNotificationData().get(notificationKey));
+ NotificationLogger.getNotificationLocation(entry);
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
rank, count, true, location);
try {
mBarService.onNotificationClick(notificationKey, nv);
- } catch (RemoteException e) {
+ } catch (RemoteException exception) {
/* ignore */
}
}
@@ -311,9 +312,9 @@ public class NotificationLockscreenUserManagerImpl implements
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return true;
}
- return isLockscreenPublicMode(mCurrentUserId)
- && getEntryManager().getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_SECRET;
+ NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
+ return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
+ && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
}
public boolean shouldShowOnKeyguard(NotificationEntry entry) {
@@ -326,8 +327,7 @@ public class NotificationLockscreenUserManagerImpl implements
&& hideSilentNotificationsOnLockscreen()) {
exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT;
} else {
- exceedsPriorityThreshold =
- !getEntryManager().getNotificationData().isAmbient(entry.getKey());
+ exceedsPriorityThreshold = !entry.getRanking().isAmbient();
}
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
@@ -467,8 +467,9 @@ public class NotificationLockscreenUserManagerImpl implements
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return true;
}
- return getEntryManager().getNotificationData().getVisibilityOverride(key) ==
- Notification.VISIBILITY_PRIVATE;
+ NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
+ return entry != null
+ && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
}
private void updateCurrentProfilesCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index d668665f062c..a98f826c0284 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -102,8 +102,7 @@ public class NotificationMediaManager implements Dumpable {
}
- // Late binding
- private NotificationEntryManager mEntryManager;
+ private final NotificationEntryManager mEntryManager;
// Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
@Nullable
@@ -258,8 +257,9 @@ public class NotificationMediaManager implements Dumpable {
if (mMediaNotificationKey == null) {
return null;
}
- synchronized (mEntryManager.getNotificationData()) {
- NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+ synchronized (mEntryManager) {
+ NotificationEntry entry = mEntryManager
+ .getActiveNotificationUnfiltered(mMediaNotificationKey);
if (entry == null || entry.expandedIcon == null) {
return null;
}
@@ -281,8 +281,9 @@ public class NotificationMediaManager implements Dumpable {
public void findAndUpdateMediaNotifications() {
boolean metaDataChanged = false;
- synchronized (mEntryManager.getNotificationData()) {
- Set<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
+ synchronized (mEntryManager) {
+ Set<NotificationEntry> allNotifications =
+ mEntryManager.getPendingAndActiveNotifications();
// Promote the media notification with a controller in 'playing' state, if any.
NotificationEntry mediaNotification = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 35f06f9d95c8..e10d27b241cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -184,8 +184,9 @@ public class NotificationRemoteInputManager implements Dumpable {
ViewGroup actionGroup = (ViewGroup) parent;
buttonIndex = actionGroup.indexOfChild(view);
}
- final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(key);
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = mEntryManager
+ .getActiveNotificationUnfiltered(key).getRanking().getRank();
// Notification may be updated before this function is executed, and thus play safe
// here and verify that the action object is still the one that where the click happens.
@@ -202,7 +203,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(
- mEntryManager.getNotificationData().get(key));
+ mEntryManager.getActiveNotificationUnfiltered(key));
final NotificationVisibility nv =
NotificationVisibility.obtain(key, rank, count, true, location);
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 20a3e35791c4..ef733a967840 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -140,8 +140,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
Assert.isMainThread();
beginUpdate();
- ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
- .getActiveNotifications();
+ List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
@@ -339,7 +338,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
}
for (ExpandableNotificationRow remove : toRemove) {
parent.removeChildNotification(remove);
- if (mEntryManager.getNotificationData().get(
+ if (mEntryManager.getActiveNotificationUnfiltered(
remove.getStatusBarNotification().getKey()) == null) {
// We only want to add an animation if the view is completely removed
// otherwise it's just a transfer
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 7bdb21d0eac5..40f8e394f054 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -73,8 +73,8 @@ public class SmartReplyController {
public void smartActionClicked(
NotificationEntry entry, int actionIndex, Notification.Action action,
boolean generatedByAssistant) {
- final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(entry.getKey());
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = entry.getRanking().getRank();
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(entry);
final NotificationVisibility nv = NotificationVisibility.obtain(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 9b312341c583..e48e81957225 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -125,22 +125,21 @@ public class ActivityLaunchAnimator {
return mAnimationRunning;
}
- class AnimationRunner extends IRemoteAnimationRunner.Stub {
+ private class AnimationRunner extends IRemoteAnimationRunner.Stub {
- private final ExpandableNotificationRow mSourceNotification;
- private final ExpandAnimationParameters mParams;
+ private ExpandableNotificationRow mSourceNotification;
+ private final ExpandAnimationParameters mParams = new ExpandAnimationParameters();
private final Rect mWindowCrop = new Rect();
private final float mNotificationCornerRadius;
private float mCornerRadius;
private boolean mIsFullScreenLaunch = true;
private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
- public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
- mSourceNotification = sourceNofitication;
- mParams = new ExpandAnimationParameters();
- mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification);
- mNotificationCornerRadius = Math.max(mSourceNotification.getCurrentTopRoundness(),
- mSourceNotification.getCurrentBottomRoundness());
+ AnimationRunner(ExpandableNotificationRow sourceNotification) {
+ mSourceNotification = sourceNotification;
+ mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(sourceNotification);
+ mNotificationCornerRadius = Math.max(sourceNotification.getCurrentTopRoundness(),
+ sourceNotification.getCurrentBottomRoundness());
}
@Override
@@ -155,6 +154,7 @@ public class ActivityLaunchAnimator {
setAnimationPending(false);
invokeCallback(iRemoteAnimationFinishedCallback);
mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+ mSourceNotification = null;
return;
}
@@ -254,6 +254,7 @@ public class ActivityLaunchAnimator {
mCallback.onExpandAnimationFinished(mIsFullScreenLaunch);
applyParamsToNotification(null);
applyParamsToNotificationList(null);
+ mSourceNotification = null;
}
}
@@ -281,6 +282,7 @@ public class ActivityLaunchAnimator {
mSourceNotification.post(() -> {
setAnimationPending(false);
mCallback.onLaunchAnimationCancelled();
+ mSourceNotification = null;
});
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 314dc04e574f..015c32348bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -37,14 +37,14 @@ import javax.inject.Singleton
*/
@Singleton
class BypassHeadsUpNotifier @Inject constructor(
- private val context: Context,
- private val bypassController: KeyguardBypassController,
- private val statusBarStateController: StatusBarStateController,
- private val headsUpManager: HeadsUpManagerPhone,
- private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
- private val mediaManager: NotificationMediaManager,
- tunerService: TunerService) : StatusBarStateController.StateListener,
- NotificationMediaManager.MediaListener {
+ private val context: Context,
+ private val bypassController: KeyguardBypassController,
+ private val statusBarStateController: StatusBarStateController,
+ private val headsUpManager: HeadsUpManagerPhone,
+ private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
+ private val mediaManager: NotificationMediaManager,
+ tunerService: TunerService
+) : StatusBarStateController.StateListener, NotificationMediaManager.MediaListener {
private lateinit var entryManager: NotificationEntryManager
private var currentMediaEntry: NotificationEntry? = null
@@ -77,7 +77,8 @@ class BypassHeadsUpNotifier @Inject constructor(
override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
val previous = currentMediaEntry
- var newEntry = entryManager.notificationData.get(mediaManager.mediaNotificationKey)
+ var newEntry = entryManager
+ .getActiveNotificationUnfiltered(mediaManager.mediaNotificationKey)
if (!NotificationMediaManager.isPlayingState(state)) {
newEntry = null
}
@@ -101,7 +102,7 @@ class BypassHeadsUpNotifier @Inject constructor(
*/
private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
if (!isAutoHeadsUpAllowed()) {
- return false;
+ return false
}
if (entry.isSensitive) {
// filter sensitive notifications
@@ -111,7 +112,7 @@ class BypassHeadsUpNotifier @Inject constructor(
// filter notifications invisible on Keyguard
return false
}
- if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+ if (entryManager.getActiveNotificationUnfiltered(entry.key) != null) {
// filter notifications not the active list currently
return false
}
@@ -125,7 +126,7 @@ class BypassHeadsUpNotifier @Inject constructor(
/**
* @return {@code true} if autoHeadsUp is possible right now.
*/
- private fun isAutoHeadsUpAllowed() : Boolean {
+ private fun isAutoHeadsUpAllowed(): Boolean {
if (!enabled) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index df78fa3fd4a4..06949208c2bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -99,7 +99,8 @@ public interface NotificationEntryListener {
/**
* Called whenever notification ranking changes, in response to
* {@link NotificationListenerService#onNotificationRankingUpdate}. This is called after
- * NotificationData has processed the update and notifications have been re-sorted and filtered.
+ * NotificationEntryManager has processed the update and notifications have been re-sorted
+ * and filtered.
*
* @param rankingMap provides access to ranking information on currently active notifications
*/
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 13d90ffdfca2..7a58097f3ec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,10 +18,12 @@ package com.android.systemui.statusbar.notification;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.Log;
@@ -36,9 +38,8 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.logging.NotifEvent;
import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -46,12 +47,15 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+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;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -62,9 +66,29 @@ import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * NotificationEntryManager is responsible for the adding, removing, and updating of notifications.
- * It also handles tasks such as their inflation and their interaction with other
- * Notification.*Manager objects.
+ * NotificationEntryManager is responsible for the adding, removing, and updating of
+ * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
+ * with other Notification.*Manager objects.
+ *
+ * We track notification entries through this lifecycle:
+ * 1. Pending
+ * 2. Active
+ * 3. Sorted / filtered (visible)
+ *
+ * Every entry spends some amount of time in the pending state, while it is being inflated. Once
+ * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
+ * user. After an entry makes its way into the active state, we sort and filter the entire set to
+ * repopulate the visible set.
+ *
+ * There are a few different things that other classes may be interested in, and most of them
+ * involve the current set of notifications. Here's a brief overview of things you may want to know:
+ * @see #getVisibleNotifications() for the visible set
+ * @see #getActiveNotificationUnfiltered(String) to check if a key exists
+ * @see #getPendingNotificationsIterator() for an iterator over the pending notifications
+ * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list
+ * @see #getPendingAndActiveNotifications() to get the entire set of Notifications that we're
+ * aware of
+ * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns
*/
@Singleton
public class NotificationEntryManager implements
@@ -78,12 +102,23 @@ public class NotificationEntryManager implements
/**
* Used when a notification is removed and it doesn't have a reason that maps to one of the
* reasons defined in NotificationListenerService
- * (e.g. {@link NotificationListenerService.REASON_CANCEL})
+ * (e.g. {@link NotificationListenerService#REASON_CANCEL})
*/
public static final int UNDEFINED_DISMISS_REASON = 0;
+ /** Pending notifications are ones awaiting inflation */
@VisibleForTesting
protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
+ /**
+ * Active notifications have been inflated / prepared and could become visible, but may get
+ * filtered out if for instance they are not for the current user
+ */
+ private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
+ @VisibleForTesting
+ /** This is the list of "active notifications for this user in this context" */
+ protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+ private final List<NotificationEntry> mReadOnlyNotifications =
+ Collections.unmodifiableList(mSortedAndFiltered);
private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications =
new ArrayMap<>();
@@ -92,10 +127,12 @@ public class NotificationEntryManager implements
private NotificationRemoteInputManager mRemoteInputManager;
private NotificationRowBinder mNotificationRowBinder;
+ private final KeyguardEnvironment mKeyguardEnvironment;
+ private final NotificationGroupManager mGroupManager;
+ private final NotificationRankingManager mRankingManager;
+
private NotificationPresenter mPresenter;
- private NotificationListenerService.RankingMap mLatestRankingMap;
- @VisibleForTesting
- protected NotificationData mNotificationData;
+ private RankingMap mLatestRankingMap;
private NotifLog mNotifLog;
@VisibleForTesting
@@ -129,10 +166,14 @@ public class NotificationEntryManager implements
@Inject
public NotificationEntryManager(
- NotificationData notificationData,
- NotifLog notifLog) {
- mNotificationData = notificationData;
+ NotifLog notifLog,
+ NotificationGroupManager groupManager,
+ NotificationRankingManager rankingManager,
+ KeyguardEnvironment keyguardEnvironment) {
mNotifLog = notifLog;
+ mGroupManager = groupManager;
+ mRankingManager = rankingManager;
+ mKeyguardEnvironment = keyguardEnvironment;
}
/** Adds a {@link NotificationEntryListener}. */
@@ -171,7 +212,6 @@ public class NotificationEntryManager implements
NotificationListContainer listContainer,
HeadsUpManager headsUpManager) {
mPresenter = presenter;
- mNotificationData.setHeadsUpManager(headsUpManager);
}
/** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -188,10 +228,6 @@ public class NotificationEntryManager implements
UNDEFINED_DISMISS_REASON));
}
- public NotificationData getNotificationData() {
- return mNotificationData;
- }
-
@Override
public void onReorderingAllowed() {
updateNotifications("reordering is now allowed");
@@ -212,10 +248,17 @@ public class NotificationEntryManager implements
}
private NotificationVisibility obtainVisibility(String key) {
- final int rank = mNotificationData.getRank(key);
- final int count = mNotificationData.getActiveNotifications().size();
+ NotificationEntry e = mActiveNotifications.get(key);
+ final int rank;
+ if (e != null) {
+ rank = e.getRanking().getRank();
+ } else {
+ rank = 0;
+ }
+
+ final int count = mActiveNotifications.size();
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(getNotificationData().get(key));
+ NotificationLogger.getNotificationLocation(getActiveNotificationUnfiltered(key));
return NotificationVisibility.obtain(key, rank, count, true, location);
}
@@ -227,7 +270,7 @@ public class NotificationEntryManager implements
mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.getSbn(), null,
"PendingNotification aborted. " + reason);
}
- NotificationEntry addedEntry = mNotificationData.get(key);
+ NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
if (addedEntry != null) {
addedEntry.abortTask();
mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getSbn(),
@@ -258,13 +301,13 @@ public class NotificationEntryManager implements
// If there was an async task started after the removal, we don't want to add it back to
// the list, otherwise we might get leaks.
if (!entry.isRowRemoved()) {
- boolean isNew = mNotificationData.get(entry.getKey()) == null;
+ boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null;
if (isNew) {
for (NotificationEntryListener listener : mNotificationEntryListeners) {
mNotifLog.log(NotifEvent.INFLATED, entry);
listener.onEntryInflated(entry, inflatedFlags);
}
- mNotificationData.add(entry);
+ addActiveNotification(entry);
updateNotifications("onAsyncInflationFinished");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationAdded(entry);
@@ -278,8 +321,34 @@ public class NotificationEntryManager implements
}
}
+ /**
+ * Equivalent to the old NotificationData#add
+ * @param entry - an entry which is prepared for display
+ */
+ private void addActiveNotification(NotificationEntry entry) {
+ Assert.isMainThread();
+
+ mActiveNotifications.put(entry.getKey(), entry);
+ mGroupManager.onEntryAdded(entry);
+ updateRankingAndSort(mRankingManager.getRankingMap(), "addEntryInternalInternal");
+ }
+
+ /**
+ * Available so that tests can directly manipulate the list of active notifications easily
+ *
+ * @param entry the entry to add directly to the visible notification map
+ */
+ @VisibleForTesting
+ public void addActiveNotificationForTest(NotificationEntry entry) {
+ mActiveNotifications.put(entry.getKey(), entry);
+ mGroupManager.onEntryAdded(entry);
+
+ reapplyFilterAndSort("addVisibleNotification");
+ }
+
+
@Override
- public void removeNotification(String key, NotificationListenerService.RankingMap ranking,
+ public void removeNotification(String key, RankingMap ranking,
int reason) {
removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
false /* removedByUser */, reason);
@@ -287,7 +356,7 @@ public class NotificationEntryManager implements
private void removeNotificationInternal(
String key,
- @Nullable NotificationListenerService.RankingMap ranking,
+ @Nullable RankingMap ranking,
@Nullable NotificationVisibility visibility,
boolean forceRemove,
boolean removedByUser,
@@ -300,7 +369,7 @@ public class NotificationEntryManager implements
return;
}
- final NotificationEntry entry = mNotificationData.get(key);
+ final NotificationEntry entry = getActiveNotificationUnfiltered(key);
boolean lifetimeExtended = false;
// Notification was canceled before it got inflated
@@ -355,8 +424,7 @@ public class NotificationEntryManager implements
// Let's remove the children if this was a summary
handleGroupSummaryRemoved(key);
-
- mNotificationData.remove(key, ranking);
+ removeVisibleNotification(key);
updateNotifications("removeNotificationInternal");
Dependency.get(LeakDetector.class).trackGarbage(entry);
removedByUser |= entryDismissed;
@@ -381,7 +449,7 @@ public class NotificationEntryManager implements
*
*/
private void handleGroupSummaryRemoved(String key) {
- NotificationEntry entry = mNotificationData.get(key);
+ NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
if (entry.getSbn().getOverrideGroupKey() != null && !entry.isRowDismissed()) {
// We don't want to remove children for autobundled notifications as they are not
@@ -413,13 +481,14 @@ public class NotificationEntryManager implements
}
private void addNotificationInternal(StatusBarNotification notification,
- NotificationListenerService.RankingMap rankingMap) throws InflationException {
+ RankingMap rankingMap) throws InflationException {
String key = notification.getKey();
if (DEBUG) {
Log.d(TAG, "addNotification key=" + key);
}
- mNotificationData.updateRanking(rankingMap, "addNotificationInternal");
+ updateRankingAndSort(rankingMap, "addNotificationInternal");
+
Ranking ranking = new Ranking();
rankingMap.getRanking(key, ranking);
@@ -439,8 +508,7 @@ public class NotificationEntryManager implements
}
@Override
- public void addNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) {
+ public void addNotification(StatusBarNotification notification, RankingMap ranking) {
try {
addNotificationInternal(notification, ranking);
} catch (InflationException e) {
@@ -449,12 +517,12 @@ public class NotificationEntryManager implements
}
private void updateNotificationInternal(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) throws InflationException {
+ RankingMap ranking) throws InflationException {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
abortExistingInflation(key, "updateNotification");
- NotificationEntry entry = mNotificationData.get(key);
+ NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry == null) {
return;
}
@@ -463,7 +531,11 @@ public class NotificationEntryManager implements
// to keep its lifetime extended.
cancelLifetimeExtension(entry);
- mNotificationData.update(entry, ranking, notification, "updateNotificationInternal");
+ updateRankingAndSort(ranking, "updateNotificationInternal");
+ StatusBarNotification oldSbn = entry.getSbn();
+ entry.setSbn(notification);
+ mGroupManager.onEntryUpdated(entry, oldSbn);
+
mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.getSbn(), entry.getRanking());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
@@ -486,8 +558,7 @@ public class NotificationEntryManager implements
}
@Override
- public void updateNotification(StatusBarNotification notification,
- NotificationListenerService.RankingMap ranking) {
+ public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
try {
updateNotificationInternal(notification, ranking);
} catch (InflationException e) {
@@ -500,16 +571,16 @@ public class NotificationEntryManager implements
* @param reason why the notifications are updating
*/
public void updateNotifications(String reason) {
- mNotificationData.filterAndSort(reason);
+ reapplyFilterAndSort(reason);
if (mPresenter != null) {
mPresenter.updateNotificationViews();
}
}
@Override
- public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
+ public void updateNotificationRanking(RankingMap rankingMap) {
List<NotificationEntry> entries = new ArrayList<>();
- entries.addAll(mNotificationData.getActiveNotifications());
+ entries.addAll(getVisibleNotifications());
entries.addAll(mPendingNotifications.values());
// Has a copy of the current UI adjustments.
@@ -523,7 +594,7 @@ public class NotificationEntryManager implements
}
// Populate notification entries from the new rankings.
- mNotificationData.updateRanking(rankingMap, "updateNotificationRanking");
+ updateRankingAndSort(rankingMap, "updateNotificationRanking");
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
@@ -542,8 +613,7 @@ public class NotificationEntryManager implements
}
}
- private void updateRankingOfPendingNotifications(
- @Nullable NotificationListenerService.RankingMap rankingMap) {
+ private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) {
if (rankingMap == null) {
return;
}
@@ -565,23 +635,35 @@ public class NotificationEntryManager implements
}
/**
- * @return all notification we're currently aware of (both pending and visible notifications)
+ * @return all notifications we're currently aware of (both pending and active notifications)
*/
- public Set<NotificationEntry> getAllNotifs() {
+ public Set<NotificationEntry> getPendingAndActiveNotifications() {
Set<NotificationEntry> allNotifs = new HashSet<>(mPendingNotifications.values());
- allNotifs.addAll(mNotificationData.getActiveNotifications());
+ allNotifs.addAll(mSortedAndFiltered);
return allNotifs;
}
/**
+ * Use this method to retrieve a notification entry that has been prepared for presentation.
+ * Note that the notification may be filtered out and never shown to the user.
+ *
+ * @see #getVisibleNotifications() for the currently sorted and filtered list
+ *
+ * @return a {@link NotificationEntry} if it has been prepared, else null
+ */
+ public NotificationEntry getActiveNotificationUnfiltered(String key) {
+ return mActiveNotifications.get(key);
+ }
+
+ /**
* Gets the pending or visible notification entry with the given key. Returns null if
* notification doesn't exist.
*/
- public NotificationEntry getPendingOrCurrentNotif(String key) {
+ public NotificationEntry getPendingOrActiveNotif(String key) {
if (mPendingNotifications.containsKey(key)) {
return mPendingNotifications.get(key);
} else {
- return mNotificationData.get(key);
+ return mActiveNotifications.get(key);
}
}
@@ -608,4 +690,136 @@ public class NotificationEntryManager implements
}
return mNotificationRowBinder;
}
+
+ /*
+ * -----
+ * Annexed from NotificationData below:
+ * Some of these methods may be redundant but require some reworking to remove. For now
+ * we'll try to keep the behavior the same and can simplify these interfaces in another pass
+ */
+
+ /** Internalization of NotificationData#remove */
+ private void removeVisibleNotification(String key) {
+ // no need to synchronize if we're on the main thread dawg
+ Assert.isMainThread();
+
+ NotificationEntry removed = mActiveNotifications.remove(key);
+
+ if (removed == null) return;
+ mGroupManager.onEntryRemoved(removed);
+ }
+
+ /** @return list of active notifications filtered for the current user */
+ public List<NotificationEntry> getActiveNotificationsForCurrentUser() {
+ Assert.isMainThread();
+ ArrayList<NotificationEntry> filtered = new ArrayList<>();
+
+ final int len = mActiveNotifications.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mActiveNotifications.valueAt(i);
+ final StatusBarNotification sbn = entry.getSbn();
+ if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
+ continue;
+ }
+ filtered.add(entry);
+ }
+
+ return filtered;
+ }
+
+ //TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking
+ /**
+ * @param rankingMap the {@link RankingMap} to apply to the current notification list
+ * @param reason the reason for calling this method, for {@link NotifLog}
+ */
+ public void updateRanking(RankingMap rankingMap, String reason) {
+ updateRankingAndSort(rankingMap, reason);
+ }
+
+ /** Resorts / filters the current notification set with the current RankingMap */
+ public void reapplyFilterAndSort(String reason) {
+ updateRankingAndSort(mRankingManager.getRankingMap(), reason);
+ }
+
+ /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
+ private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
+ mSortedAndFiltered.clear();
+ mSortedAndFiltered.addAll(mRankingManager.updateRanking(
+ rankingMap, mActiveNotifications.values(), reason));
+ }
+
+ /** dump the current active notification list. Called from StatusBar */
+ public void dump(PrintWriter pw, String indent) {
+ pw.println("NotificationEntryManager");
+ int filteredLen = mSortedAndFiltered.size();
+ pw.print(indent);
+ pw.println("active notifications: " + filteredLen);
+ int active;
+ for (active = 0; active < filteredLen; active++) {
+ NotificationEntry e = mSortedAndFiltered.get(active);
+ dumpEntry(pw, indent, active, e);
+ }
+ synchronized (mActiveNotifications) {
+ int totalLen = mActiveNotifications.size();
+ pw.print(indent);
+ pw.println("inactive notifications: " + (totalLen - active));
+ int inactiveCount = 0;
+ for (int i = 0; i < totalLen; i++) {
+ NotificationEntry entry = mActiveNotifications.valueAt(i);
+ if (!mSortedAndFiltered.contains(entry)) {
+ dumpEntry(pw, indent, inactiveCount, entry);
+ inactiveCount++;
+ }
+ }
+ }
+ }
+
+ private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+ pw.print(indent);
+ pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
+ StatusBarNotification n = e.getSbn();
+ pw.print(indent);
+ pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+ + e.getRanking().getImportance());
+ pw.print(indent);
+ pw.println(" notification=" + n.getNotification());
+ }
+
+ /**
+ * This is the answer to the question "what notifications should the user be seeing right now?"
+ * These are sorted and filtered, and directly inform the notification shade what to show
+ *
+ * @return A read-only list of the currently active notifications
+ */
+ public List<NotificationEntry> getVisibleNotifications() {
+ return mReadOnlyNotifications;
+ }
+
+ /** @return A count of the active notifications */
+ public int getActiveNotificationsCount() {
+ return mReadOnlyNotifications.size();
+ }
+
+ /**
+ * @return {@code true} if there is at least one notification that should be visible right now
+ */
+ public boolean hasActiveNotifications() {
+ return mReadOnlyNotifications.size() != 0;
+ }
+
+ /*
+ * End annexation
+ * -----
+ */
+
+
+ /**
+ * Provides access to keyguard state and user settings dependent data.
+ */
+ public interface KeyguardEnvironment {
+ /** true if the device is provisioned (should always be true in practice) */
+ boolean isDeviceProvisioned();
+ /** true if the notification is for the current profiles */
+ boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index b1164093acdd..e5f44bd3b9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,7 +28,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +43,7 @@ public class NotificationFilter {
private final NotificationGroupManager mGroupManager = Dependency.get(
NotificationGroupManager.class);
- private NotificationData.KeyguardEnvironment mEnvironment;
+ private NotificationEntryManager.KeyguardEnvironment mEnvironment;
private ShadeController mShadeController;
private ForegroundServiceController mFsc;
private NotificationLockscreenUserManager mUserManager;
@@ -52,9 +51,9 @@ public class NotificationFilter {
@Inject
public NotificationFilter() {}
- private NotificationData.KeyguardEnvironment getEnvironment() {
+ private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
if (mEnvironment == null) {
- mEnvironment = Dependency.get(NotificationData.KeyguardEnvironment.class);
+ mEnvironment = Dependency.get(NotificationEntryManager.KeyguardEnvironment.class);
}
return mEnvironment;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
deleted file mode 100644
index a0229d16d6eb..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ /dev/null
@@ -1,500 +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 static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.logging.NotifEvent;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
- private static final String TAG = "NotificationData";
-
- private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
- /**
- * These dependencies are late init-ed
- */
- private KeyguardEnvironment mEnvironment;
- private NotificationMediaManager mMediaManager;
-
- private HeadsUpManager mHeadsUpManager;
-
- private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
- private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-
- private final NotificationGroupManager mGroupManager =
- Dependency.get(NotificationGroupManager.class);
-
- private RankingMap mRankingMap;
- private final Ranking mTmpRanking = new Ranking();
- private final boolean mUsePeopleFiltering;
- private final NotifLog mNotifLog;
- private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
-
- @Inject
- public NotificationData(
- NotificationSectionsFeatureManager sectionsFeatureManager,
- NotifLog notifLog,
- PeopleNotificationIdentifier peopleNotificationIdentifier) {
- mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
- mNotifLog = notifLog;
- mPeopleNotificationIdentifier = peopleNotificationIdentifier;
- }
-
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
- @VisibleForTesting
- protected final Comparator<NotificationEntry> mRankingComparator =
- new Comparator<NotificationEntry>() {
- @Override
- public int compare(NotificationEntry a, NotificationEntry b) {
- final StatusBarNotification na = a.getSbn();
- final StatusBarNotification nb = b.getSbn();
- int aRank = getRank(a.getKey());
- int bRank = getRank(b.getKey());
-
- boolean aPeople = isPeopleNotification(a);
- boolean bPeople = isPeopleNotification(b);
-
- boolean aMedia = isImportantMedia(a);
- boolean bMedia = isImportantMedia(b);
-
- boolean aSystemMax = isSystemMax(a);
- boolean bSystemMax = isSystemMax(b);
-
- boolean aHeadsUp = a.isRowHeadsUp();
- boolean bHeadsUp = b.isRowHeadsUp();
-
- if (mUsePeopleFiltering && aPeople != bPeople) {
- return aPeople ? -1 : 1;
- } else if (aHeadsUp != bHeadsUp) {
- return aHeadsUp ? -1 : 1;
- } else if (aHeadsUp) {
- // Provide consistent ranking with headsUpManager
- return mHeadsUpManager.compare(a, b);
- } else if (aMedia != bMedia) {
- // Upsort current media notification.
- return aMedia ? -1 : 1;
- } else if (aSystemMax != bSystemMax) {
- // Upsort PRIORITY_MAX system notifications
- return aSystemMax ? -1 : 1;
- } else if (a.isHighPriority() != b.isHighPriority()) {
- return -1 * Boolean.compare(a.isHighPriority(), b.isHighPriority());
- } else if (aRank != bRank) {
- return aRank - bRank;
- } else {
- return Long.compare(nb.getNotification().when, na.getNotification().when);
- }
- }
- };
-
- private KeyguardEnvironment getEnvironment() {
- if (mEnvironment == null) {
- mEnvironment = Dependency.get(KeyguardEnvironment.class);
- }
- return mEnvironment;
- }
-
- private NotificationMediaManager getMediaManager() {
- if (mMediaManager == null) {
- mMediaManager = Dependency.get(NotificationMediaManager.class);
- }
- return mMediaManager;
- }
-
- /**
- * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
- *
- * <p>
- * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
- * when the environment changes.
- * <p>
- * Don't hold on to or modify the returned list.
- */
- public ArrayList<NotificationEntry> getActiveNotifications() {
- return mSortedAndFiltered;
- }
-
- public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
- synchronized (mEntries) {
- final int len = mEntries.size();
- ArrayList<NotificationEntry> filteredForUser = new ArrayList<>(len);
-
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- final StatusBarNotification sbn = entry.getSbn();
- if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
- continue;
- }
- filteredForUser.add(entry);
- }
- return filteredForUser;
- }
- }
-
- public NotificationEntry get(String key) {
- return mEntries.get(key);
- }
-
- public void add(NotificationEntry entry) {
- synchronized (mEntries) {
- mEntries.put(entry.getSbn().getKey(), entry);
- }
- mGroupManager.onEntryAdded(entry);
-
- updateRankingAndSort(mRankingMap, "addEntry=" + entry.getSbn());
- }
-
- public NotificationEntry remove(String key, RankingMap ranking) {
- NotificationEntry removed;
- synchronized (mEntries) {
- removed = mEntries.remove(key);
- }
- if (removed == null) return null;
- mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking, "removeEntry=" + removed.getSbn());
- return removed;
- }
-
- /** Updates the given notification entry with the provided ranking. */
- public void update(
- NotificationEntry entry,
- RankingMap ranking,
- StatusBarNotification notification,
- String reason) {
- updateRanking(ranking, reason);
- final StatusBarNotification oldNotification = entry.getSbn();
- entry.setSbn(notification);
- mGroupManager.onEntryUpdated(entry, oldNotification);
- }
-
- /**
- * Update ranking and trigger a re-sort
- */
- public void updateRanking(RankingMap ranking, String reason) {
- updateRankingAndSort(ranking, reason);
- }
-
- /**
- * Returns true if this notification should be displayed in the high-priority notifications
- * section
- */
- public boolean isHighPriority(StatusBarNotification statusBarNotification) {
- if (mRankingMap != null) {
- getRanking(statusBarNotification.getKey(), mTmpRanking);
- if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || hasHighPriorityCharacteristics(
- mTmpRanking.getChannel(), statusBarNotification)) {
- return true;
- }
- if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
- final ArrayList<NotificationEntry> logicalChildren =
- mGroupManager.getLogicalChildren(statusBarNotification);
- for (NotificationEntry child : logicalChildren) {
- if (isHighPriority(child.getSbn())) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean hasHighPriorityCharacteristics(NotificationChannel channel,
- StatusBarNotification statusBarNotification) {
-
- if (isImportantOngoing(statusBarNotification.getNotification())
- || statusBarNotification.getNotification().hasMediaSession()
- || hasPerson(statusBarNotification.getNotification())
- || hasStyle(statusBarNotification.getNotification(),
- Notification.MessagingStyle.class)) {
- // Users who have long pressed and demoted to silent should not see the notification
- // in the top section
- if (channel != null && channel.hasUserSetImportance()) {
- return false;
- }
- return true;
- }
-
- return false;
- }
-
- private boolean isImportantOngoing(Notification notification) {
- return notification.isForegroundService()
- && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW;
- }
-
- private boolean hasStyle(Notification notification, Class targetStyle) {
- Class<? extends Notification.Style> style = notification.getNotificationStyle();
- return targetStyle.equals(style);
- }
-
- private boolean hasPerson(Notification notification) {
- // TODO: cache favorite and recent contacts to check contact affinity
- ArrayList<Person> people = notification.extras != null
- ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
- : new ArrayList<>();
- return people != null && !people.isEmpty();
- }
-
- public boolean isAmbient(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isAmbient();
- }
- return false;
- }
-
- public int getVisibilityOverride(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getVisibilityOverride();
- }
- return Ranking.VISIBILITY_NO_OVERRIDE;
- }
-
- public List<SnoozeCriterion> getSnoozeCriteria(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getSnoozeCriteria();
- }
- return null;
- }
-
- public NotificationChannel getChannel(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getChannel();
- }
- return null;
- }
-
- public int getRank(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getRank();
- }
- return 0;
- }
-
- private boolean isImportantMedia(NotificationEntry e) {
- int importance = e.getRanking().getImportance();
- boolean media = e.getKey().equals(getMediaManager().getMediaNotificationKey())
- && importance > NotificationManager.IMPORTANCE_MIN;
-
- return media;
- }
-
- private boolean isSystemMax(NotificationEntry e) {
- int importance = e.getRanking().getImportance();
- boolean sys = importance >= NotificationManager.IMPORTANCE_HIGH
- && isSystemNotification(e.getSbn());
-
- return sys;
- }
-
- public boolean shouldHide(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isSuspended();
- }
- return false;
- }
-
- private void updateRankingAndSort(RankingMap rankingMap, String reason) {
- if (rankingMap != null) {
- mRankingMap = rankingMap;
- synchronized (mEntries) {
- final int len = mEntries.size();
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- Ranking newRanking = new Ranking();
- if (!getRanking(entry.getKey(), newRanking)) {
- continue;
- }
- entry.setRanking(newRanking);
-
- final StatusBarNotification oldSbn = entry.getSbn().cloneLight();
- final String overrideGroupKey = newRanking.getOverrideGroupKey();
- if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
- entry.getSbn().setOverrideGroupKey(overrideGroupKey);
- mGroupManager.onEntryUpdated(entry, oldSbn);
- }
- entry.setIsHighPriority(isHighPriority(entry.getSbn()));
- }
- }
- }
- filterAndSort(reason);
- }
-
- /**
- * Get the ranking from the current ranking map.
- *
- * @param key the key to look up
- * @param outRanking the ranking to populate
- *
- * @return {@code true} if the ranking was properly obtained.
- */
- @VisibleForTesting
- protected boolean getRanking(String key, Ranking outRanking) {
- return mRankingMap.getRanking(key, outRanking);
- }
-
- // TODO: This should not be public. Instead the Environment should notify this class when
- // anything changed, and this class should call back the UI so it updates itself.
- /**
- * Filters and sorts the list of notification entries
- */
- public void filterAndSort(String reason) {
- mNotifLog.log(NotifEvent.FILTER_AND_SORT, reason);
- mSortedAndFiltered.clear();
-
- synchronized (mEntries) {
- final int len = mEntries.size();
- for (int i = 0; i < len; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
-
- if (mNotificationFilter.shouldFilterOut(entry)) {
- continue;
- }
-
- mSortedAndFiltered.add(entry);
- }
- }
-
- Collections.sort(mSortedAndFiltered, mRankingComparator);
-
- int bucket = BUCKET_PEOPLE;
- for (NotificationEntry e : mSortedAndFiltered) {
- assignBucketForEntry(e);
- if (e.getBucket() < bucket) {
- android.util.Log.wtf(TAG, "Detected non-contiguous bucket!");
- }
- bucket = e.getBucket();
- }
- }
-
- private void assignBucketForEntry(NotificationEntry e) {
- boolean isHeadsUp = e.isRowHeadsUp();
- boolean isMedia = isImportantMedia(e);
- boolean isSystemMax = isSystemMax(e);
-
- setBucket(e, isHeadsUp, isMedia, isSystemMax);
- }
-
- private void setBucket(
- NotificationEntry e,
- boolean isHeadsUp,
- boolean isMedia,
- boolean isSystemMax) {
- if (mUsePeopleFiltering && isPeopleNotification(e)) {
- e.setBucket(BUCKET_PEOPLE);
- } else if (isHeadsUp || isMedia || isSystemMax || e.isHighPriority()) {
- e.setBucket(BUCKET_ALERTING);
- } else {
- e.setBucket(BUCKET_SILENT);
- }
- }
-
- private boolean isPeopleNotification(NotificationEntry e) {
- return mPeopleNotificationIdentifier.isPeopleNotification(e.getSbn());
- }
-
- public void dump(PrintWriter pw, String indent) {
- int filteredLen = mSortedAndFiltered.size();
- pw.print(indent);
- pw.println("active notifications: " + filteredLen);
- int active;
- for (active = 0; active < filteredLen; active++) {
- NotificationEntry e = mSortedAndFiltered.get(active);
- dumpEntry(pw, indent, active, e);
- }
- synchronized (mEntries) {
- int totalLen = mEntries.size();
- pw.print(indent);
- pw.println("inactive notifications: " + (totalLen - active));
- int inactiveCount = 0;
- for (int i = 0; i < totalLen; i++) {
- NotificationEntry entry = mEntries.valueAt(i);
- if (!mSortedAndFiltered.contains(entry)) {
- dumpEntry(pw, indent, inactiveCount, entry);
- inactiveCount++;
- }
- }
- }
- }
-
- private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
- getRanking(e.getKey(), mTmpRanking);
- pw.print(indent);
- pw.println(" [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
- StatusBarNotification n = e.getSbn();
- pw.print(indent);
- pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
- + mTmpRanking.getImportance());
- pw.print(indent);
- pw.println(" notification=" + n.getNotification());
- }
-
- private static boolean isSystemNotification(StatusBarNotification sbn) {
- String sbnPackage = sbn.getPackageName();
- return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
- }
-
- /**
- * Provides access to keyguard state and user settings dependent data.
- */
- public interface KeyguardEnvironment {
- boolean isDeviceProvisioned();
- boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
new file mode 100644
index 000000000000..8bce528bab8c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -0,0 +1,260 @@
+/*
+ * 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.app.Notification
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.NotificationManager.IMPORTANCE_MIN
+import android.app.Person
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.NotificationListenerService.RankingMap
+import android.service.notification.StatusBarNotification
+import com.android.internal.annotations.VisibleForTesting
+
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationFilter
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.logging.NotifEvent
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+
+import java.util.Objects
+import java.util.ArrayList
+
+import javax.inject.Inject
+
+import kotlin.Comparator
+
+import dagger.Lazy
+
+private const val TAG = "NotifRankingManager"
+
+/**
+ * NotificationRankingManager is responsible for holding on to the most recent [RankingMap], and
+ * updating SystemUI's set of [NotificationEntry]s with their own ranking. It also sorts and filters
+ * a set of entries (but retains none of them). We also set buckets on the entries here since
+ * bucketing is tied closely to sorting.
+ *
+ * For the curious: this class is one iteration closer to null of what used to be called
+ * NotificationData.java.
+ */
+open class NotificationRankingManager @Inject constructor(
+ private val mediaManagerLazy: Lazy<NotificationMediaManager>,
+ private val groupManager: NotificationGroupManager,
+ private val headsUpManager: HeadsUpManager,
+ private val notifFilter: NotificationFilter,
+ private val notifLog: NotifLog,
+ sectionsFeatureManager: NotificationSectionsFeatureManager
+) {
+
+ var rankingMap: RankingMap? = null
+ protected set
+ private val mediaManager by lazy {
+ mediaManagerLazy.get()
+ }
+ private val usePeopleFiltering: Boolean = sectionsFeatureManager.isFilteringEnabled()
+ private val rankingComparator: Comparator<NotificationEntry> = Comparator { a, b ->
+ val na = a.sbn
+ val nb = b.sbn
+ val aRank = a.ranking.rank
+ val bRank = b.ranking.rank
+
+ val aMedia = isImportantMedia(a)
+ val bMedia = isImportantMedia(b)
+
+ val aSystemMax = a.isSystemMax()
+ val bSystemMax = b.isSystemMax()
+
+ val aHeadsUp = a.isRowHeadsUp
+ val bHeadsUp = b.isRowHeadsUp
+
+ if (usePeopleFiltering && a.isPeopleNotification() != b.isPeopleNotification()) {
+ if (a.isPeopleNotification()) -1 else 1
+ } else if (aHeadsUp != bHeadsUp) {
+ if (aHeadsUp) -1 else 1
+ } else if (aHeadsUp) {
+ // Provide consistent ranking with headsUpManager
+ headsUpManager.compare(a, b)
+ } else if (aMedia != bMedia) {
+ // Upsort current media notification.
+ if (aMedia) -1 else 1
+ } else if (aSystemMax != bSystemMax) {
+ // Upsort PRIORITY_MAX system notifications
+ if (aSystemMax) -1 else 1
+ } else if (a.isHighPriority != b.isHighPriority) {
+ -1 * java.lang.Boolean.compare(a.isHighPriority, b.isHighPriority)
+ } else if (aRank != bRank) {
+ aRank - bRank
+ } else {
+ nb.notification.`when`.compareTo(na.notification.`when`)
+ }
+ }
+
+ private fun isImportantMedia(entry: NotificationEntry): Boolean {
+ val importance = entry.ranking.importance
+ return entry.key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
+ }
+
+ @VisibleForTesting
+ protected fun isHighPriority(entry: NotificationEntry): Boolean {
+ if (entry.importance >= IMPORTANCE_DEFAULT ||
+ hasHighPriorityCharacteristics(entry)) {
+ return true
+ }
+
+ if (groupManager.isSummaryOfGroup(entry.sbn)) {
+ val logicalChildren = groupManager.getLogicalChildren(entry.sbn)
+ for (child in logicalChildren) {
+ if (isHighPriority(child)) {
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+
+ private fun hasHighPriorityCharacteristics(entry: NotificationEntry): Boolean {
+ val c = entry.channel
+ val n = entry.sbn.notification
+
+ if (((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
+ n.hasMediaSession() ||
+ n.hasPerson() ||
+ n.hasStyle(Notification.MessagingStyle::class.java))) {
+ // Users who have long pressed and demoted to silent should not see the notification
+ // in the top section
+ if (c != null && c.hasUserSetImportance()) {
+ return false
+ }
+
+ return true
+ }
+
+ return false
+ }
+
+ fun updateRanking(
+ newRankingMap: RankingMap?,
+ entries: Collection<NotificationEntry>,
+ reason: String
+ ): List<NotificationEntry> {
+ val eSeq = entries.asSequence()
+
+ // TODO: may not be ideal to guard on null here, but this code is implementing exactly what
+ // NotificationData used to do
+ if (newRankingMap != null) {
+ rankingMap = newRankingMap
+ updateRankingForEntries(eSeq)
+ }
+
+ val filtered: Sequence<NotificationEntry>
+ synchronized(this) {
+ filtered = filterAndSortLocked(eSeq, reason)
+ }
+
+ return filtered.toList()
+ }
+
+ /** Uses the [rankingComparator] to sort notifications which aren't filtered */
+ private fun filterAndSortLocked(
+ entries: Sequence<NotificationEntry>,
+ reason: String
+ ): Sequence<NotificationEntry> {
+ notifLog.log(NotifEvent.FILTER_AND_SORT, reason)
+
+ return entries.filter { !notifFilter.shouldFilterOut(it) }
+ .sortedWith(rankingComparator)
+ .map {
+ assignBucketForEntry(it)
+ it
+ }
+ }
+
+ private fun assignBucketForEntry(entry: NotificationEntry) {
+ val isHeadsUp = entry.isRowHeadsUp
+ val isMedia = isImportantMedia(entry)
+ val isSystemMax = entry.isSystemMax()
+ setBucket(entry, isHeadsUp, isMedia, isSystemMax)
+ }
+
+ private fun setBucket(
+ entry: NotificationEntry,
+ isHeadsUp: Boolean,
+ isMedia: Boolean,
+ isSystemMax: Boolean
+ ) {
+ if (usePeopleFiltering && entry.hasAssociatedPeople()) {
+ entry.bucket = BUCKET_PEOPLE
+ } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
+ entry.bucket = BUCKET_ALERTING
+ } else {
+ entry.bucket = BUCKET_SILENT
+ }
+ }
+
+ private fun updateRankingForEntries(entries: Sequence<NotificationEntry>) {
+ rankingMap?.let { rankingMap ->
+ synchronized(entries) {
+ entries.forEach { entry ->
+ val newRanking = Ranking()
+ if (!rankingMap.getRanking(entry.key, newRanking)) {
+ return@forEach
+ }
+ entry.ranking = newRanking
+
+ val oldSbn = entry.sbn.cloneLight()
+ val newOverrideGroupKey = newRanking.overrideGroupKey
+ if (!Objects.equals(oldSbn.overrideGroupKey, newOverrideGroupKey)) {
+ entry.sbn.overrideGroupKey = newOverrideGroupKey
+ // TODO: notify group manager here?
+ groupManager.onEntryUpdated(entry, oldSbn)
+ }
+ entry.setIsHighPriority(isHighPriority(entry))
+ }
+ }
+ }
+ }
+}
+
+// Convenience functions
+private fun NotificationEntry.isSystemMax(): Boolean {
+ return importance >= IMPORTANCE_HIGH && sbn.isSystemNotification()
+}
+
+private fun StatusBarNotification.isSystemNotification(): Boolean {
+ return "android" == packageName || "com.android.systemui" == packageName
+}
+
+private fun Notification.hasPerson(): Boolean {
+ val people: ArrayList<Person> =
+ (extras?.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)) ?: ArrayList()
+ return people.isNotEmpty()
+}
+
+private fun Notification.hasStyle(targetStyleClass: Class<*>): Boolean {
+ return targetStyleClass == notificationStyle
+}
+
+private fun NotificationEntry.isPeopleNotification(): Boolean =
+ sbn.notification.hasStyle(Notification.MessagingStyle::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 52fd07937546..1c0a9d4f14af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -32,7 +32,6 @@ import android.view.ViewGroup;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.UiOffloadThread;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -61,7 +60,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
Dependency.get(NotificationGroupManager.class);
private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
- private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
Dependency.get(NotificationInterruptionStateProvider.class);
@@ -81,16 +79,20 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
- private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
+ private final NotificationLogger mNotificationLogger;
- public NotificationRowBinderImpl(Context context, boolean allowLongPress,
+ public NotificationRowBinderImpl(
+ Context context,
+ boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ NotificationLogger logger) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mNotificationLogger = logger;
}
private NotificationRemoteInputManager getRemoteInputManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 90c5502bd119..77ccf19f65ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -43,9 +43,9 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.inject.Inject;
@@ -113,7 +113,7 @@ public class NotificationLogger implements StateListener {
public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
- // 1. Loop over mNotificationData entries:
+ // 1. Loop over active entries:
// A. Keep list of visible notifications.
// B. Keep list of previously hidden, now visible notifications.
// 2. Compute no-longer visible notifications by removing currently
@@ -121,8 +121,7 @@ public class NotificationLogger implements StateListener {
// notifications.
// 3. Report newly visible and no-longer visible notifications.
// 4. Keep currently visible notifications for next report.
- ArrayList<NotificationEntry> activeNotifications = mEntryManager
- .getNotificationData().getActiveNotifications();
+ List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
NotificationEntry entry = activeNotifications.get(i);
@@ -403,7 +402,7 @@ public class NotificationLogger implements StateListener {
*/
public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
NotificationVisibility.NotificationLocation location =
- getNotificationLocation(mEntryManager.getNotificationData().get(key));
+ getNotificationLocation(mEntryManager.getActiveNotificationUnfiltered(key));
mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index b12c76c750a8..d1b9a87c1ddc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1546,9 +1546,11 @@ public class NotificationContentView extends FrameLayout {
}
if (mExpandedWrapper != null) {
mExpandedWrapper.setRemoved();
+ mMediaTransferManager.setRemoved(mExpandedChild);
}
if (mContractedWrapper != null) {
mContractedWrapper.setRemoved();
+ mMediaTransferManager.setRemoved(mContractedChild);
}
if (mHeadsUpWrapper != null) {
mHeadsUpWrapper.setRemoved();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index f90e561dece1..f67cd1bef281 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -319,7 +319,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
packageName,
row.getEntry().getChannel(),
row.getUniqueChannels(),
- sbn,
+ row.getEntry(),
mCheckSaveListener,
onSettingsClick,
onAppSettingsClick,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 148d83b5ab5c..a9a4804a2be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -65,7 +65,10 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.bubbles.BubbleExperimentConfig;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import java.lang.annotation.Retention;
@@ -99,6 +102,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// standard controls
private static final int ACTION_ALERT = 5;
+ private TextView mBubbleDescriptionView;
private TextView mPriorityDescriptionView;
private TextView mSilentDescriptionView;
@@ -116,6 +120,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private Set<NotificationChannel> mUniqueChannelsInRow;
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
+ private boolean mStartedAsBubble;
private boolean mWasShownHighPriority;
private boolean mPressedApply;
private boolean mPresentingChannelEditorDialog = false;
@@ -125,8 +130,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
* level; non-null once the user takes an action which indicates an explicit preference.
*/
@Nullable private Integer mChosenImportance;
+ /**
+ * The last bubble setting chosen by the user. Null if the user has not chosen a bubble level;
+ * non-null once the user takes an action which indicates an explicit preference.
+ */
+ @Nullable private Boolean mChosenBubbleEnabled;
private boolean mIsSingleDefaultChannel;
private boolean mIsNonblockable;
+ private boolean mIsBubbleable;
+ private NotificationEntry mEntry;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
private boolean mIsDeviceProvisioned;
@@ -137,18 +149,27 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private NotificationGuts mGutsContainer;
private Drawable mPkgIcon;
+ private BubbleController mBubbleController;
+
/** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
+ @VisibleForTesting
+ boolean mSkipPost = false;
+
/**
* String that describes how the user exit or quit out of this view, also used as a counter tag.
*/
private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+
// used by standard ui
private OnClickListener mOnAlert = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
mChosenImportance = IMPORTANCE_DEFAULT;
+ if (mStartedAsBubble) {
+ mChosenBubbleEnabled = false;
+ }
applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */);
};
@@ -156,9 +177,19 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private OnClickListener mOnSilent = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
mChosenImportance = IMPORTANCE_LOW;
+ if (mStartedAsBubble) {
+ mChosenBubbleEnabled = false;
+ }
applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */);
};
+ /** Used by standard ui (in an experiment) {@see BubbleExperimentConfig#allowNotifBubbleMenu} */
+ private OnClickListener mOnBubble = v -> {
+ mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ mChosenBubbleEnabled = true;
+ applyAlertingBehavior(BEHAVIOR_BUBBLE, true /* userTriggered */);
+ };
+
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
mPressedApply = true;
@@ -224,6 +255,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
protected void onFinishInflate() {
super.onFinishInflate();
+ mBubbleDescriptionView = findViewById(R.id.bubble_summary);
mPriorityDescriptionView = findViewById(R.id.alert_summary);
mSilentDescriptionView = findViewById(R.id.silence_summary);
}
@@ -251,7 +283,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
final String pkg,
final NotificationChannel notificationChannel,
final Set<NotificationChannel> uniqueChannelsInRow,
- final StatusBarNotification sbn,
+ final NotificationEntry entry,
final CheckSaveListener checkSaveListener,
final OnSettingsClickListener onSettingsClick,
final OnAppSettingsClickListener onAppSettingsClick,
@@ -261,7 +293,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean wasShownHighPriority)
throws RemoteException {
bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel,
- uniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
+ uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick,
onAppSettingsClick, isDeviceProvisioned, isNonblockable,
false /* isBlockingHelper */,
importance, wasShownHighPriority);
@@ -274,7 +306,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
String pkg,
NotificationChannel notificationChannel,
Set<NotificationChannel> uniqueChannelsInRow,
- StatusBarNotification sbn,
+ NotificationEntry entry,
CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
@@ -288,10 +320,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mMetricsLogger = Dependency.get(MetricsLogger.class);
mVisualStabilityManager = visualStabilityManager;
mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
+ mBubbleController = Dependency.get(BubbleController.class);
mPackageName = pkg;
mUniqueChannelsInRow = uniqueChannelsInRow;
mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
- mSbn = sbn;
+ mEntry = entry;
+ mSbn = entry.getSbn();
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mAppName = mPackageName;
@@ -318,6 +352,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
&& numTotalChannels == 1;
}
+ mIsBubbleable = mEntry.getBubbleMetadata() != null;
+ mStartedAsBubble = mEntry.isBubble();
+
bindHeader();
bindChannelDetails();
@@ -365,6 +402,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
findViewById(R.id.non_configurable_text).setVisibility(GONE);
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
+ findViewById(R.id.bubble).setVisibility(mIsBubbleable ? VISIBLE : GONE);
}
View turnOffButton = findViewById(R.id.turn_off_notifications);
@@ -378,12 +416,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
View silent = findViewById(R.id.silence);
View alert = findViewById(R.id.alert);
+ View bubble = findViewById(R.id.bubble);
silent.setOnClickListener(mOnSilent);
alert.setOnClickListener(mOnAlert);
+ bubble.setOnClickListener(mOnBubble);
- applyAlertingBehavior(
- mWasShownHighPriority ? BEHAVIOR_ALERTING : BEHAVIOR_SILENT,
- false /* userTriggered */);
+ int behavior = mStartedAsBubble
+ ? BEHAVIOR_BUBBLE
+ : mWasShownHighPriority
+ ? BEHAVIOR_ALERTING
+ : BEHAVIOR_SILENT;
+ applyAlertingBehavior(behavior, false /* userTriggered */);
}
private void bindHeader() {
@@ -544,6 +587,14 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
+ if (mChosenBubbleEnabled != null && mStartedAsBubble != mChosenBubbleEnabled) {
+ if (mChosenBubbleEnabled) {
+ mBubbleController.onUserCreatedBubbleFromNotification(mEntry);
+ } else {
+ mBubbleController.onUserDemotedBubbleFromNotification(mEntry);
+ }
+ }
+
Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
bgHandler.post(
new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
@@ -553,6 +604,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
+ @Override
+ public boolean post(Runnable action) {
+ if (mSkipPost) {
+ action.run();
+ return true;
+ } else {
+ return super.post(action);
+ }
+ }
+
private void applyAlertingBehavior(@AlertingBehavior int behavior, boolean userTriggered) {
if (userTriggered) {
TransitionSet transition = new TransitionSet();
@@ -569,6 +630,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
TransitionManager.beginDelayedTransition(this, transition);
}
+ View bubble = findViewById(R.id.bubble);
View alert = findViewById(R.id.alert);
View silence = findViewById(R.id.silence);
@@ -576,33 +638,53 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
case BEHAVIOR_ALERTING:
mPriorityDescriptionView.setVisibility(VISIBLE);
mSilentDescriptionView.setVisibility(GONE);
+ mBubbleDescriptionView.setVisibility(GONE);
post(() -> {
alert.setSelected(true);
silence.setSelected(false);
+ bubble.setSelected(false);
});
break;
- case BEHAVIOR_SILENT:
+ case BEHAVIOR_SILENT:
mSilentDescriptionView.setVisibility(VISIBLE);
mPriorityDescriptionView.setVisibility(GONE);
+ mBubbleDescriptionView.setVisibility(GONE);
post(() -> {
alert.setSelected(false);
silence.setSelected(true);
+ bubble.setSelected(false);
+ });
+ break;
+
+ case BEHAVIOR_BUBBLE:
+ mBubbleDescriptionView.setVisibility(VISIBLE);
+ mSilentDescriptionView.setVisibility(GONE);
+ mPriorityDescriptionView.setVisibility(GONE);
+ post(() -> {
+ alert.setSelected(false);
+ silence.setSelected(false);
+ bubble.setSelected(true);
});
break;
+
default:
throw new IllegalArgumentException("Unrecognized alerting behavior: " + behavior);
}
boolean isAChange = mWasShownHighPriority != (behavior == BEHAVIOR_ALERTING);
+ boolean isABubbleChange = mStartedAsBubble != (behavior == BEHAVIOR_BUBBLE);
TextView done = findViewById(R.id.done);
- done.setText(isAChange ? R.string.inline_ok_button : R.string.inline_done_button);
+ done.setText((isAChange || isABubbleChange)
+ ? R.string.inline_ok_button
+ : R.string.inline_done_button);
}
private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
switch (action) {
case ACTION_UNDO:
mChosenImportance = mStartingChannelImportance;
+ mChosenBubbleEnabled = mStartedAsBubble;
break;
case ACTION_DELIVER_SILENTLY:
mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
@@ -685,6 +767,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
if (mChosenImportance != null) {
mStartingChannelImportance = mChosenImportance;
}
+ if (mChosenBubbleEnabled != null) {
+ mStartedAsBubble = mChosenBubbleEnabled;
+ }
mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
if (mIsForBlockingHelper) {
@@ -884,8 +969,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
@Retention(SOURCE)
- @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT})
+ @IntDef({BEHAVIOR_ALERTING, BEHAVIOR_SILENT, BEHAVIOR_BUBBLE})
private @interface AlertingBehavior {}
private static final int BEHAVIOR_ALERTING = 0;
private static final int BEHAVIOR_SILENT = 1;
+ private static final int BEHAVIOR_BUBBLE = 2;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index d0122c2b59b2..516d649a3bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -167,12 +167,6 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
mContext = ctx;
mMediaManager = Dependency.get(NotificationMediaManager.class);
mMetricsLogger = Dependency.get(MetricsLogger.class);
-
- if (mView instanceof MediaNotificationView) {
- MediaNotificationView mediaView = (MediaNotificationView) mView;
- mediaView.addVisibilityListener(mVisibilityListener);
- mView.addOnAttachStateChangeListener(mAttachStateListener);
- }
}
private void resolveViews() {
@@ -183,6 +177,8 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
.getParcelable(Notification.EXTRA_MEDIA_SESSION);
if (Utils.useQsMediaPlayer(mContext)) {
+ final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
+ .getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_qs_panel);
@@ -190,7 +186,8 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
mRow.getStatusBarNotification().getNotification().getSmallIcon(),
getNotificationHeader().getOriginalIconColor(),
mRow.getCurrentBackgroundTint(),
- mActions);
+ mActions,
+ compactActions);
QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_settings_panel);
bigPanel.addMediaSession(token,
@@ -210,13 +207,13 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
}
// Check for existing media controller and clean up / create as necessary
- boolean controllerUpdated = false;
+ boolean shouldUpdateListeners = false;
if (mMediaController == null || !mMediaController.getSessionToken().equals(token)) {
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaCallback);
}
mMediaController = new MediaController(mContext, token);
- controllerUpdated = true;
+ shouldUpdateListeners = true;
}
mMediaMetadata = mMediaController.getMetadata();
@@ -228,7 +225,7 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
mSeekBarView.setVisibility(View.GONE);
mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
clearTimer();
- } else if (mSeekBarView == null && controllerUpdated) {
+ } else if (mSeekBarView == null && shouldUpdateListeners) {
// Only log if the controller changed, otherwise we would log multiple times for
// the same notification when user pauses/resumes
mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
@@ -258,6 +255,16 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
mSeekBarElapsedTime = mSeekBarView.findViewById(R.id.notification_media_elapsed_time);
mSeekBarTotalTime = mSeekBarView.findViewById(R.id.notification_media_total_time);
+ shouldUpdateListeners = true;
+ }
+
+ if (shouldUpdateListeners) {
+ if (mView instanceof MediaNotificationView) {
+ MediaNotificationView mediaView = (MediaNotificationView) mView;
+ mediaView.addVisibilityListener(mVisibilityListener);
+ mView.addOnAttachStateChangeListener(mAttachStateListener);
+ }
+
if (mSeekBarTimer == null) {
if (mMediaController != null && canSeekMedia(mMediaController.getPlaybackState())) {
// Log initial state, since it will not be updated
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 0d8e30ef6988..462fa59c785c 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
@@ -696,8 +696,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
- boolean showFooterView = (showDismissView ||
- mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
+ boolean showFooterView = (showDismissView || mEntryManager.hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
@@ -5787,11 +5786,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
@@ -6400,7 +6394,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
if (mStatusBarState == StatusBarState.KEYGUARD
- && hasActiveNotifications()) {
+ && mEntryManager.hasActiveNotifications()) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
(int) (dragLengthY / mDisplayMetrics.density),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 1ecc4899d5e7..afaa593b3bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -90,14 +90,6 @@ public class DozeScrimController implements StateListener {
public void onCancelled() {
pulseFinished();
}
-
- /**
- * Whether to timeout wallpaper or not.
- */
- @Override
- public boolean shouldTimeoutWallpaper() {
- return mPulseReason == DozeEvent.PULSE_REASON_DOCKING;
- }
};
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index a1af5e855294..6aee19454cda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -233,10 +233,6 @@ public final class DozeServiceHost implements DozeHost {
mScrimController.setWakeLockScreenSensorActive(true);
}
- if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
- mStatusBarWindowViewController.suppressWakeUpGesture(true);
- }
-
boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
&& mWakeLockScreenPerformsAuth;
// Set the state to pulsing, so ScrimController will know what to do once we ask it to
@@ -257,9 +253,6 @@ public final class DozeServiceHost implements DozeHost {
callback.onPulseFinished();
mStatusBar.updateNotificationPanelTouchState();
mScrimController.setWakeLockScreenSensorActive(false);
- if (mStatusBarWindow != null) {
- mStatusBarWindowViewController.suppressWakeUpGesture(false);
- }
setPulsing(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 2c931ae1c8ef..e763496da859 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@ import android.util.Log;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import javax.inject.Inject;
@@ -42,12 +42,12 @@ public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
public KeyguardEnvironmentImpl() {
}
- @Override // NotificationData.KeyguardEnvironment
+ @Override // NotificationEntryManager.KeyguardEnvironment
public boolean isDeviceProvisioned() {
return mDeviceProvisionedController.isDeviceProvisioned();
}
- @Override // NotificationData.KeyguardEnvironment
+ @Override // NotificationEntryManager.KeyguardEnvironment
public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index 93887a6617f9..5703f0653398 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -97,7 +97,7 @@ public class LightsOutNotifController {
}
private boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ return mEntryManager.hasActiveNotifications();
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1e10b6f025f2..3554b54db99b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,7 +15,6 @@ import androidx.collection.ArrayMap;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -26,7 +25,6 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -48,7 +46,6 @@ public class NotificationIconAreaController implements DarkReceiver,
private static final long AOD_ICONS_APPEAR_DURATION = 200;
private final ContrastColorUtil mContrastColorUtil;
- private final NotificationEntryManager mEntryManager;
private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
private final StatusBarStateController mStatusBarStateController;
private final NotificationMediaManager mMediaManager;
@@ -91,7 +88,6 @@ public class NotificationIconAreaController implements DarkReceiver,
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
- mEntryManager = Dependency.get(NotificationEntryManager.class);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
@@ -247,7 +243,7 @@ public class NotificationIconAreaController implements DarkReceiver,
if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
return false;
}
- if (mEntryManager.getNotificationData().isAmbient(entry.getKey()) && !showAmbient) {
+ if (entry.getRanking().isAmbient() && !showAmbient) {
return false;
}
if (hideCurrentMedia && entry.getKey().equals(mMediaManager.getMediaNotificationKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6839fb432c0a..6176cff82f6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -3562,8 +3562,7 @@ public class NotificationPanelView extends PanelView implements
private void updateShowEmptyShadeView() {
boolean showEmptyShadeView =
- mBarState != StatusBarState.KEYGUARD &&
- mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ mBarState != StatusBarState.KEYGUARD && mEntryManager.hasActiveNotifications();
showEmptyShadeView(showEmptyShadeView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f21a9a2eba88..1454e256b75b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -46,6 +46,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -136,6 +137,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DozeParameters mDozeParameters;
+ private final DockManager mDockManager;
private final AlarmTimeout mTimeTicker;
private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
private final Handler mHandler;
@@ -192,7 +194,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
@MainResources Resources resources,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
- KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
+ DockManager dockManager) {
mScrimStateListener = lightBarController::setScrimState;
@@ -209,6 +212,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
// to make sure that text on top of it is legible.
mScrimBehindAlpha = mScrimBehindAlphaResValue;
mDozeParameters = dozeParameters;
+ mDockManager = dockManager;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
@@ -234,7 +238,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
final ScrimState[] states = ScrimState.values();
for (int i = 0; i < states.length; i++) {
- states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters);
+ states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
+ mDockManager);
states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
}
@@ -359,11 +364,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
return true;
}
- if (mState == ScrimState.PULSING
- && mCallback != null && mCallback.shouldTimeoutWallpaper()) {
- return true;
- }
-
return false;
}
@@ -520,8 +520,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* device is dozing when the light sensor is on.
*/
public void setAodFrontScrimAlpha(float alpha) {
- if (((mState == ScrimState.AOD && mDozeParameters.getAlwaysOn())
- || mState == ScrimState.PULSING) && mInFrontAlpha != alpha) {
+ if (mInFrontAlpha != alpha && shouldUpdateFrontScrimAlpha()) {
mInFrontAlpha = alpha;
updateScrims();
}
@@ -530,6 +529,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mState.PULSING.setAodFrontScrimAlpha(alpha);
}
+ private boolean shouldUpdateFrontScrimAlpha() {
+ if (mState == ScrimState.AOD
+ && (mDozeParameters.getAlwaysOn() || mDockManager.isDocked())) {
+ return true;
+ }
+
+ if (mState == ScrimState.PULSING) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* If the lock screen sensor is active.
*/
@@ -1022,10 +1034,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
default void onCancelled() {
}
- /** Returns whether to timeout wallpaper or not. */
- default boolean shouldTimeoutWallpaper() {
- return false;
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 13055ffb2f77..40f8d58ad695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import android.graphics.Color;
import android.os.Trace;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -128,10 +129,11 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
+ final boolean isDocked = mDockManager.isDocked();
mBlankScreen = mDisplayRequiresBlanking;
mFrontTint = Color.BLACK;
- mFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f;
+ mFrontAlpha = (alwaysOnEnabled || isDocked) ? mAodFrontScrimAlpha : 1f;
mBehindTint = Color.BLACK;
mBehindAlpha = ScrimController.TRANSPARENT;
@@ -258,6 +260,7 @@ public enum ScrimState {
ScrimView mScrimForBubble;
DozeParameters mDozeParameters;
+ DockManager mDockManager;
boolean mDisplayRequiresBlanking;
boolean mWallpaperSupportsAmbientMode;
boolean mHasBackdrop;
@@ -267,12 +270,13 @@ public enum ScrimState {
long mKeyguardFadingAwayDuration;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters, DockManager dockManager) {
mScrimInFront = scrimInFront;
mScrimBehind = scrimBehind;
mScrimForBubble = scrimForBubble;
mDozeParameters = dozeParameters;
+ mDockManager = dockManager;
mDisplayRequiresBlanking = dozeParameters.getDisplayNeedsBlanking();
}
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 0e1985de4371..adea8c6aa014 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1228,7 +1228,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mContext,
mAllowNotificationLongPress,
mKeyguardBypassController,
- mStatusBarStateController);
+ mStatusBarStateController,
+ mNotificationLogger);
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
@@ -2494,8 +2495,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
if (DUMPTRUCK) {
- synchronized (mEntryManager.getNotificationData()) {
- mEntryManager.getNotificationData().dump(pw, " ");
+ synchronized (mEntryManager) {
+ mEntryManager.dump(pw, " ");
}
if (false) {
@@ -2753,11 +2754,7 @@ public class StatusBar extends SystemUI implements DemoMode,
};
public void resetUserExpandedStates() {
- ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
- .getActiveNotifications();
- final int notificationCount = activeNotifications.size();
- for (int i = 0; i < notificationCount; i++) {
- NotificationEntry entry = activeNotifications.get(i);
+ for (NotificationEntry entry : mEntryManager.getVisibleNotifications()) {
entry.resetUserExpansion();
}
}
@@ -2857,8 +2854,7 @@ public class StatusBar extends SystemUI implements DemoMode,
try {
// consider the transition from peek to expanded to be a panel open,
// but not one that clears notification effects.
- int notificationLoad = mEntryManager.getNotificationData()
- .getActiveNotifications().size();
+ int notificationLoad = mEntryManager.getActiveNotificationsCount();
mBarService.onPanelRevealed(false, notificationLoad);
} catch (RemoteException ex) {
// Won't fail unless the world has ended.
@@ -2876,8 +2872,7 @@ public class StatusBar extends SystemUI implements DemoMode,
!mPresenter.isPresenterFullyCollapsed() &&
(mState == StatusBarState.SHADE
|| mState == StatusBarState.SHADE_LOCKED);
- int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
- .size();
+ int notificationLoad = mEntryManager.getActiveNotificationsCount();
if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
@@ -3862,10 +3857,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mScreenPinningRequest.showPrompt(taskId, allowCancel);
}
- public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
- }
-
@Override
public void appTransitionCancelled(int displayId) {
if (displayId == mDisplayId) {
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 64a45e16d749..1cf43cc310ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -326,12 +326,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
collapseOnMainThread();
}
- final int count =
- mEntryManager.getNotificationData().getActiveNotifications().size();
- final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+ //TODO(b/144306683): prove that this `activeEntry` is the same as `entry` above and simplify
+ // this call stack
+ NotificationEntry activeEntry =
+ mEntryManager.getActiveNotificationUnfiltered(notificationKey);
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = activeEntry != null ? activeEntry.getRanking().getRank() : 0;
NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(
- mEntryManager.getNotificationData().get(notificationKey));
+ NotificationLogger.getNotificationLocation(activeEntry);
final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
rank, count, true, location);
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 38ff86227733..30e26e57e435 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -75,7 +75,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import java.util.ArrayList;
+import java.util.List;
public class StatusBarNotificationPresenter implements NotificationPresenter,
ConfigurationController.ConfigurationListener,
@@ -252,8 +252,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
private void updateNotificationOnUiModeChanged() {
- ArrayList<NotificationEntry> userNotifications
- = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+ List<NotificationEntry> userNotifications =
+ mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
NotificationEntry entry = userNotifications.get(i);
ExpandableNotificationRow row = entry.getRow();
@@ -264,8 +264,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
private void updateNotificationsOnDensityOrFontScaleChanged() {
- ArrayList<NotificationEntry> userNotifications =
- mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+ List<NotificationEntry> userNotifications =
+ mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
NotificationEntry entry = userNotifications.get(i);
entry.onDensityOrFontScaleChanged();
@@ -326,7 +326,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
public boolean hasActiveNotifications() {
- return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ return mEntryManager.hasActiveNotifications();
}
public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index f716443cbfe1..c1328ec2a060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -35,6 +35,7 @@ import android.view.ViewStub;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -75,10 +76,10 @@ public class StatusBarWindowViewController {
private PhoneStatusBarView mStatusBarView;
private StatusBar mService;
private DragDownHelper mDragDownHelper;
- private boolean mSuppressingWakeUpGesture;
private boolean mDoubleTapEnabled;
private boolean mSingleTapEnabled;
private boolean mExpandingBelowNotch;
+ private final DockManager mDockManager;
private StatusBarWindowViewController(
StatusBarWindowView view,
@@ -97,9 +98,11 @@ public class StatusBarWindowViewController {
SysuiStatusBarStateController statusBarStateController,
DozeLog dozeLog,
DozeParameters dozeParameters,
- CommandQueue commandQueue) {
+ CommandQueue commandQueue,
+ DockManager dockManager) {
mView = view;
mFalsingManager = falsingManager;
+ mDockManager = dockManager;
// TODO: create controller for NotificationPanelView
NotificationPanelView notificationPanelView = new NotificationPanelView(
@@ -158,7 +161,7 @@ public class StatusBarWindowViewController {
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
- if (mSingleTapEnabled && !mSuppressingWakeUpGesture) {
+ if (mSingleTapEnabled && !mDockManager.isDocked()) {
mService.wakeUpIfDozing(
SystemClock.uptimeMillis(), mView, "SINGLE_TAP");
return true;
@@ -243,7 +246,7 @@ public class StatusBarWindowViewController {
@Override
public boolean shouldInterceptTouchEvent(MotionEvent ev) {
- if (mService.isDozing() && !mService.isPulsing()) {
+ if (mService.isDozing() && !mService.isPulsing() && !mDockManager.isDocked()) {
// Capture all touch events in always-on.
return true;
}
@@ -445,10 +448,6 @@ public class StatusBarWindowViewController {
mDragDownHelper = dragDownHelper;
}
- public void suppressWakeUpGesture(boolean suppress) {
- mSuppressingWakeUpGesture = suppress;
- }
-
/**
* When we're launching an affordance, like double pressing power to open camera.
*/
@@ -495,6 +494,7 @@ public class StatusBarWindowViewController {
private final CommandQueue mCommandQueue;
private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private final StatusBarWindowView mView;
+ private final DockManager mDockManager;
@Inject
public Builder(
@@ -513,7 +513,8 @@ public class StatusBarWindowViewController {
DozeLog dozeLog,
DozeParameters dozeParameters,
CommandQueue commandQueue,
- SuperStatusBarViewFactory superStatusBarViewFactory) {
+ SuperStatusBarViewFactory superStatusBarViewFactory,
+ DockManager dockManager) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -530,8 +531,8 @@ public class StatusBarWindowViewController {
mDozeParameters = dozeParameters;
mCommandQueue = commandQueue;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
-
mView = mSuperStatusBarViewFactory.getStatusBarWindowView();
+ mDockManager = dockManager;
}
/**
@@ -563,7 +564,8 @@ public class StatusBarWindowViewController {
mStatusBarStateController,
mDozeLog,
mDozeParameters,
- mCommandQueue);
+ mCommandQueue,
+ mDockManager);
}
}
}
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 dba3b923db4f..ddacc3aedce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -185,6 +185,9 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
+ // NOTE: This receiver could run before this method returns, as it's not dispatching
+ // on the main thread and BroadcastDispatcher may not need to register with Context.
+ // The receiver will return immediately if the view does not have a Handler yet.
mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
@@ -197,11 +200,9 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
mCurrentUserId = mCurrentUserTracker.getCurrentUserId();
}
- // NOTE: It's safe to do these after registering the receiver since the receiver always runs
- // in the main thread, therefore the receiver can't run before this method returns.
-
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = Calendar.getInstance(TimeZone.getDefault());
+ mClockFormatString = "";
// Make sure we update to the current time
updateClock();
@@ -227,10 +228,16 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // If the handler is null, it means we received a broadcast while the view has not
+ // finished being attached or in the process of being detached.
+ // In that case, do not post anything.
+ Handler handler = getHandler();
+ if (handler == null) return;
+
String action = intent.getAction();
if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
- getHandler().post(() -> {
+ handler.post(() -> {
mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
if (mClockFormat != null) {
mClockFormat.setTimeZone(mCalendar.getTimeZone());
@@ -238,14 +245,14 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
});
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
final Locale newLocale = getResources().getConfiguration().locale;
- getHandler().post(() -> {
+ handler.post(() -> {
if (!newLocale.equals(mLocale)) {
mLocale = newLocale;
mClockFormatString = ""; // force refresh
}
});
}
- getHandler().post(() -> updateClock());
+ handler.post(() -> updateClock());
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index d48876778590..2e26711a3578 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -23,6 +23,7 @@ import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.icu.text.DateFormat;
import android.icu.text.DisplayContext;
+import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
@@ -47,6 +48,12 @@ public class DateView extends TextView {
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // If the handler is null, it means we received a broadcast while the view has not
+ // finished being attached or in the process of being detached.
+ // In that case, do not post anything.
+ Handler handler = getHandler();
+ if (handler == null) return;
+
final String action = intent.getAction();
if (Intent.ACTION_TIME_TICK.equals(action)
|| Intent.ACTION_TIME_CHANGED.equals(action)
@@ -55,9 +62,9 @@ public class DateView extends TextView {
if (Intent.ACTION_LOCALE_CHANGED.equals(action)
|| Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
// need to get a fresh date format
- getHandler().post(() -> mDateFormat = null);
+ handler.post(() -> mDateFormat = null);
}
- getHandler().post(() -> updateClock());
+ handler.post(() -> updateClock());
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index bae51b6ebd9e..3f25bb63a614 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -23,6 +23,8 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings.Global;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -50,6 +52,7 @@ import java.io.PrintWriter;
import java.util.BitSet;
import java.util.concurrent.Executor;
import java.util.Objects;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -477,6 +480,18 @@ public class MobileSignalController extends SignalController<
}
/**
+ * Extracts the CellSignalStrengthCdma from SignalStrength then returns the level
+ */
+ private final int getCdmaLevel() {
+ List<CellSignalStrengthCdma> signalStrengthCdma =
+ mSignalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class);
+ if (!signalStrengthCdma.isEmpty()) {
+ return signalStrengthCdma.get(0).getLevel();
+ }
+ return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ }
+
+ /**
* Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
* mDataState, and mSimState. It should be called any time one of these is updated.
* This will call listeners if necessary.
@@ -491,7 +506,7 @@ public class MobileSignalController extends SignalController<
&& mSignalStrength != null;
if (mCurrentState.connected) {
if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
- mCurrentState.level = mSignalStrength.getCdmaLevel();
+ mCurrentState.level = getCdmaLevel();
} else {
mCurrentState.level = mSignalStrength.getLevel();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index a60ca6201419..49ada1a5e41e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -158,7 +158,7 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference
String demoTime = "1010"; // 10:10, a classic choice of horologists
try {
- String[] versionParts = android.os.Build.VERSION.RELEASE.split("\\.");
+ String[] versionParts = android.os.Build.VERSION.RELEASE_OR_CODENAME.split("\\.");
int majorVersion = Integer.valueOf(versionParts[0]);
demoTime = String.format("%02d00", majorVersion % 24);
} catch (IllegalArgumentException ex) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 25a5139bf661..1c2a2fa53bea 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -72,10 +72,11 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
);
@Inject
- public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator) {
+ public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
+ VolumeDialogControllerImpl volumeDialogController) {
mContext = context;
mKeyguardViewMediator = keyguardViewMediator;
- mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
+ mController = volumeDialogController;
mController.setUserActivityListener(this);
// Allow plugins to reference the VolumeDialogController.
Dependency.get(PluginDependencyProvider.class)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index fc57981aea24..02c699fc30f7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -52,6 +52,7 @@ import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.annotations.GuardedBy;
@@ -74,6 +75,8 @@ import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Singleton;
+import dagger.Lazy;
+
/**
* Source of truth for all state / events related to the volume dialog. No presentation.
*
@@ -115,7 +118,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final Context mContext;
private AudioManager mAudio;
private IAudioService mAudioService;
- private final Optional<StatusBar> mStatusBarOptional;
+ private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final NotificationManager mNoMan;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
@@ -142,9 +145,9 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Inject
public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher,
- Optional<StatusBar> statusBarOptional) {
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
mContext = context.getApplicationContext();
- mStatusBarOptional = statusBarOptional;
+ mStatusBarOptionalLazy = statusBarOptionalLazy;
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
@@ -448,12 +451,14 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private boolean shouldShowUI(int flags) {
// if status bar isn't null, check if phone is in AOD, else check flags
// since we could be using a different status bar
- return mStatusBarOptional.map(statusBar ->
- statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
- && statusBar.getWakefulnessState()
- != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
- && statusBar.isDeviceInteractive()
- && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog).orElse(
+ return mStatusBarOptionalLazy.map(statusBarLazy -> {
+ StatusBar statusBar = statusBarLazy.get();
+ return statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+ && statusBar.getWakefulnessState()
+ != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
+ && statusBar.isDeviceInteractive() && (flags & AudioManager.FLAG_SHOW_UI) != 0
+ && mShowVolumeDialog;
+ }).orElse(
mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0);
}
@@ -1078,10 +1083,12 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
addStream(token, "onRemoteUpdate");
+
int stream = 0;
synchronized (mRemoteStreams) {
stream = mRemoteStreams.get(token);
}
+ Slog.d(TAG, "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume());
boolean changed = mState.states.indexOfKey(stream) < 0;
final StreamState ss = streamStateW(stream);
ss.dynamic = true;
@@ -1097,8 +1104,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
changed = true;
}
if (changed) {
- if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
- + " of " + ss.levelMax);
+ Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level + " of " + ss.levelMax);
mCallbacks.onStateChanged(mState);
}
}
@@ -1111,11 +1117,13 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
stream = mRemoteStreams.get(token);
}
final boolean showUI = shouldShowUI(flags);
+ Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI);
boolean changed = updateActiveStreamW(stream);
if (showUI) {
changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
}
if (changed) {
+ Slog.d(TAG, "onRemoteChanged: updatingState");
mCallbacks.onStateChanged(mState);
}
if (showUI) {
@@ -1128,7 +1136,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
int stream = 0;
synchronized (mRemoteStreams) {
if (!mRemoteStreams.containsKey(token)) {
- if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+ Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+ "aborting remote removed for token:" + token.toString());
return;
}
@@ -1165,7 +1173,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
synchronized (mRemoteStreams) {
if (!mRemoteStreams.containsKey(token)) {
mRemoteStreams.put(token, mNextStream);
- if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
+ Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
+ " from token + " + token.toString());
mNextStream++;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
new file mode 100644
index 000000000000..f3487fb5e2d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -0,0 +1,199 @@
+/*
+ * 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.wm;
+
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.IDisplayWindowListener;
+import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayWindowRotationController;
+import android.view.WindowContainerTransaction;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
+ * frozen the screen, it will call into this class. This will then call all registered local
+ * controllers and give them a chance to queue up task changes to be applied synchronously with that
+ * rotation.
+ */
+@Singleton
+public class DisplayWindowController {
+ private final Handler mHandler;
+
+ private final ArrayList<OnDisplayWindowRotationController> mRotationControllers =
+ new ArrayList<>();
+ private final ArrayList<OnDisplayWindowRotationController> mTmpControllers = new ArrayList<>();
+
+ private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
+ private final ArrayList<DisplayWindowListener> mDisplayChangedListeners = new ArrayList<>();
+
+ private final IDisplayWindowRotationController mDisplayRotationController =
+ new IDisplayWindowRotationController.Stub() {
+ @Override
+ public void onRotateDisplay(int displayId, final int fromRotation,
+ final int toRotation, IDisplayWindowRotationCallback callback) {
+ mHandler.post(() -> {
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ synchronized (mRotationControllers) {
+ mTmpControllers.clear();
+ // Make a local copy in case the handlers add/remove themselves.
+ mTmpControllers.addAll(mRotationControllers);
+ }
+ for (OnDisplayWindowRotationController c : mTmpControllers) {
+ c.onRotateDisplay(displayId, fromRotation, toRotation, t);
+ }
+ try {
+ callback.continueRotateDisplay(toRotation, t);
+ } catch (RemoteException e) {
+ }
+ });
+ }
+ };
+
+ private final IDisplayWindowListener mDisplayContainerListener =
+ new IDisplayWindowListener.Stub() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ if (mDisplays.get(displayId) != null) {
+ return;
+ }
+ DisplayRecord record = new DisplayRecord();
+ record.mDisplayId = displayId;
+ mDisplays.put(displayId, record);
+ for (DisplayWindowListener l : mDisplayChangedListeners) {
+ l.onDisplayAdded(displayId);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mHandler.post(() -> {
+ synchronized (mDisplays) {
+ for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+ mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
+ }
+ mDisplays.remove(displayId);
+ }
+ });
+ }
+ };
+
+ @Inject
+ public DisplayWindowController(@MainHandler Handler mainHandler) {
+ mHandler = mainHandler;
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
+ mDisplayContainerListener);
+ WindowManagerGlobal.getWindowManagerService().setDisplayWindowRotationController(
+ mDisplayRotationController);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to register hierarchy listener");
+ }
+ }
+
+ /**
+ * Add a display window-container listener. It will get notified when displays are
+ * added/removed from the WM hierarchy.
+ */
+ public void addDisplayWindowListener(DisplayWindowListener listener) {
+ synchronized (mDisplays) {
+ if (mDisplayChangedListeners.contains(listener)) {
+ return;
+ }
+ mDisplayChangedListeners.add(listener);
+ for (int i = 0; i < mDisplays.size(); ++i) {
+ listener.onDisplayAdded(mDisplays.keyAt(i));
+ }
+ }
+ }
+
+ /**
+ * Remove a display window-container listener.
+ */
+ public void removeDisplayWindowListener(DisplayWindowListener listener) {
+ synchronized (mDisplays) {
+ mDisplayChangedListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Adds a display rotation controller.
+ */
+ public void addRotationController(OnDisplayWindowRotationController controller) {
+ synchronized (mRotationControllers) {
+ mRotationControllers.add(controller);
+ }
+ }
+
+ /**
+ * Removes a display rotation controller.
+ */
+ public void removeRotationController(OnDisplayWindowRotationController controller) {
+ synchronized (mRotationControllers) {
+ mRotationControllers.remove(controller);
+ }
+ }
+
+ private static class DisplayRecord {
+ int mDisplayId;
+ }
+
+ /**
+ * Gets notified when a display is added/removed to the WM hierarchy.
+ *
+ * @see IDisplayWindowListener
+ */
+ public interface DisplayWindowListener {
+ /**
+ * Called when a display has been added to the WM hierarchy.
+ */
+ void onDisplayAdded(int displayId);
+
+ /**
+ * Called when a display is removed.
+ */
+ void onDisplayRemoved(int displayId);
+ }
+
+ /**
+ * Give a controller a chance to queue up configuration changes to execute as part of a
+ * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
+ */
+ public interface OnDisplayWindowRotationController {
+ /**
+ * Called before the display is rotated. Contents of this method must run synchronously.
+ * @param displayId Id of display that is rotating.
+ * @param fromRotation starting rotation of the display.
+ * @param toRotation target rotation of the display (after rotating).
+ * @param t A task transaction to populate.
+ */
+ void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ WindowContainerTransaction t);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index e63b6d6670fd..02a3766fb3b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -102,7 +102,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
public void testAppOps_appOpAddedToForegroundNotif() {
// GIVEN a notification associated with a foreground service
NotificationEntry entry = addFgEntry();
- when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+ when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry);
// WHEN we are notified of a new app op for this notification
mFsc.onAppOpChanged(
@@ -123,7 +123,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
// GIVEN a foreground service associated notification that already has the correct app op
NotificationEntry entry = addFgEntry();
entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA);
- when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+ when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry);
// WHEN we are notified of the same app op for this notification
mFsc.onAppOpChanged(
@@ -143,7 +143,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
public void testAppOps_appOpNotAddedToUnrelatedNotif() {
// GIVEN no notification entries correspond to the newly updated appOp
NotificationEntry entry = addFgEntry();
- when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null);
+ when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(null);
// WHEN a new app op is detected
mFsc.onAppOpChanged(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
index fbb8e0c171cd..f832b7bf769f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
@@ -65,7 +65,7 @@ public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
@Mock private AssistUtils mMockAssistUtils;
@Mock private Handler mMockHandler;
- @Mock private PhenotypeHelper mMockPhenotypeHelper;
+ @Mock private DeviceConfigHelper mMockDeviceConfigHelper;
@Mock private AssistHandleOffBehavior mMockOffBehavior;
@Mock private AssistHandleLikeHomeBehavior mMockLikeHomeBehavior;
@Mock private AssistHandleReminderExpBehavior mMockReminderExpBehavior;
@@ -97,7 +97,7 @@ public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
mMockAssistUtils,
mMockHandler,
() -> mMockAssistHandleViewController,
- mMockPhenotypeHelper,
+ mMockDeviceConfigHelper,
behaviorMap,
mMockNavigationModeController,
mMockDumpController);
@@ -216,7 +216,7 @@ public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
public void showAndGo_doesNothingIfRecentlyHidden() {
// Arrange
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
- when(mMockPhenotypeHelper.getLong(
+ when(mMockDeviceConfigHelper.getLong(
eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
anyLong())).thenReturn(10000L);
mAssistHandleBehaviorController.showAndGo();
@@ -297,7 +297,7 @@ public class AssistHandleBehaviorControllerTest extends SysuiTestCase {
public void showAndGoDelayed_doesNothingIfRecentlyHidden() {
// Arrange
when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
- when(mMockPhenotypeHelper.getLong(
+ when(mMockDeviceConfigHelper.getLong(
eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
anyLong())).thenReturn(10000L);
mAssistHandleBehaviorController.showAndGo();
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 a7c02045667d..8c9f75950eb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -72,7 +72,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -141,8 +140,6 @@ public class BubbleControllerTest extends SysuiTestCase {
private ExpandableNotificationRow mNonBubbleNotifRow;
@Mock
- private NotificationData mNotificationData;
- @Mock
private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
@Mock
private BubbleController.BubbleExpandListener mBubbleExpandListener;
@@ -183,10 +180,9 @@ public class BubbleControllerTest extends SysuiTestCase {
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
// Return non-null notification data from the NEM
- when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
- when(mNotificationData.get(mRow.getEntry().getKey())).thenReturn(mRow.getEntry());
- when(mNotificationData.getChannel(mRow.getEntry().getKey())).thenReturn(
- mRow.getEntry().getChannel());
+ when(mNotificationEntryManager
+ .getActiveNotificationUnfiltered(mRow.getEntry().getKey())).thenReturn(
+ mRow.getEntry());
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 32361cd0c1d5..a9be30ba82a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.bubbles;
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -72,6 +74,8 @@ public class BubbleDataTest extends SysuiTestCase {
private NotificationEntry mEntryB2;
private NotificationEntry mEntryB3;
private NotificationEntry mEntryC1;
+ private NotificationEntry mEntryInterruptive;
+ private NotificationEntry mEntryDismissed;
private Bubble mBubbleA1;
private Bubble mBubbleA2;
@@ -110,6 +114,13 @@ public class BubbleDataTest extends SysuiTestCase {
mEntryB3 = createBubbleEntry(1, "b3", "package.b");
mEntryC1 = createBubbleEntry(1, "c1", "package.c");
+ mEntryInterruptive = createBubbleEntry(1, "interruptive", "package.d");
+ modifyRanking(mEntryInterruptive)
+ .setVisuallyInterruptive(true)
+ .build();
+
+ mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
+
mBubbleA1 = new Bubble(mContext, mEntryA1);
mBubbleA2 = new Bubble(mContext, mEntryA2);
mBubbleA3 = new Bubble(mContext, mEntryA3);
@@ -160,6 +171,77 @@ public class BubbleDataTest extends SysuiTestCase {
assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_USER_GESTURE);
}
+ @Test
+ public void ifSuppress_hideFlyout() {
+ // Setup
+ mBubbleData.setListener(mListener);
+
+ // Test
+ mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ true, /* showInShade */
+ true);
+
+ // Verify
+ verifyUpdateReceived();
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.addedBubble.showFlyoutForBubble()).isFalse();
+ }
+
+ @Test
+ public void ifInterruptiveAndNotSuppressed_thenShowFlyout() {
+ // Setup
+ mBubbleData.setListener(mListener);
+
+ // Test
+ mBubbleData.notificationEntryUpdated(mEntryInterruptive, /* suppressFlyout */
+ false, /* showInShade */
+ true);
+
+ // Verify
+ verifyUpdateReceived();
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.addedBubble.showFlyoutForBubble()).isTrue();
+ }
+
+ @Test
+ public void sameUpdate_InShade_thenHideFlyout() {
+ // Setup
+ mBubbleData.setListener(mListener);
+
+ // Test
+ mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
+ true);
+ verifyUpdateReceived();
+
+ mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
+ true);
+ verifyUpdateReceived();
+
+ // Verify
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.updatedBubble.showFlyoutForBubble()).isFalse();
+ }
+
+ @Test
+ public void sameUpdate_NotInShade_showFlyout() {
+ // Setup
+ mBubbleData.setListener(mListener);
+ setMetadataFlags(mEntryDismissed,
+ Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, /* enableFlag */ true);
+
+ // Test
+ mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ false,
+ /* showInShade */ false);
+ verifyUpdateReceived();
+
+ mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */
+ false, /* showInShade */ false);
+ verifyUpdateReceived();
+
+ // Verify
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.updatedBubble.showFlyoutForBubble()).isTrue();
+ }
+
// COLLAPSED / ADD
/**
@@ -854,6 +936,23 @@ public class BubbleDataTest extends SysuiTestCase {
}
/**
+ * Sets the bubble metadata flags for this entry. These flags are normally set by
+ * NotificationManagerService when the notification is sent, however, these tests do not
+ * go through that path so we set them explicitly when testing.
+ */
+ private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
+ Notification.BubbleMetadata bubbleMetadata =
+ entry.getSbn().getNotification().getBubbleMetadata();
+ int flags = bubbleMetadata.getFlags();
+ if (enableFlag) {
+ flags |= flag;
+ } else {
+ flags &= ~flag;
+ }
+ bubbleMetadata.setFlags(flags);
+ }
+
+ /**
* No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
* required for BubbleData functionality and verification. NotificationTestHelper is used only
* as a convenience to create a Notification w/BubbleMetadata.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
index 839b5e4472c6..466c1c48fcd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
@@ -37,6 +37,11 @@ public class DockManagerFake implements DockManager {
return false;
}
+ @Override
+ public boolean isHidden() {
+ return false;
+ }
+
public void setDockEvent(int event) {
mCallback.onEvent(event);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 98ec45947f79..c9bb4016c7bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -20,16 +20,11 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-import android.os.Looper;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
@@ -49,10 +44,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class DozeDockHandlerTest extends SysuiTestCase {
- @Mock
- private DozeMachine mMachine;
- @Mock
- private DozeHost mHost;
+ @Mock private DozeMachine mMachine;
private AmbientDisplayConfiguration mConfig;
private DockManagerFake mDockManagerFake;
private DozeDockHandler mDockHandler;
@@ -61,146 +53,52 @@ public class DozeDockHandlerTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mConfig = DozeConfigurationUtil.createMockConfig();
- doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
-
mDockManagerFake = spy(new DockManagerFake());
- mDockHandler = new DozeDockHandler(mContext, mMachine, mHost, mConfig,
- Handler.createAsync(Looper.myLooper()), mDockManagerFake);
- }
-
- @Test
- public void testDockEventListener_registerAndUnregister() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-
- verify(mDockManagerFake).addListener(any());
-
- mDockHandler.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
-
- verify(mDockManagerFake).removeListener(any());
- }
-
- @Test
- public void testOnEvent_dockedWhenDoze_requestPulse() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
+ mDockHandler = new DozeDockHandler(mConfig, mMachine, mDockManagerFake);
- verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
- }
-
- @Test
- public void testOnEvent_dockedWhenDozeAoD_requestPulse() {
+ doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
-
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
-
- verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
}
@Test
- public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(State.DOZE_PULSING);
- when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
-
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
-
- verify(mHost).stopPulsing();
+ public void transitionToInitialized_registersDockEventListener() {
+ verify(mDockManagerFake).addListener(any());
}
@Test
- public void testOnEvent_undockedWhenPulsing_requestPulseOut() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
- when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
+ public void transitionToFinish_unregistersDockEventListener() {
+ mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.FINISH);
- mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
-
- verify(mHost).stopPulsing();
+ verify(mDockManagerFake).removeListener(any());
}
@Test
- public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
- mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
+ public void onEvent_docked_requestsDockedAodState() {
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
- verify(mHost, never()).stopPulsing();
+ verify(mMachine).requestState(eq(State.DOZE_AOD_DOCKED));
}
@Test
- public void testOnEvent_undockedWhenDozeAndEnabledAoD_requestDozeAoD() {
- doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
+ public void onEvent_noneWhileEnabledAod_requestsAodState() {
mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
verify(mMachine).requestState(eq(State.DOZE_AOD));
}
@Test
- public void testTransitionToDoze_whenDocked_requestPulse() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
- mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE);
-
- TestableLooper.get(this).processAllMessages();
-
- verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
- }
-
- @Test
- public void testTransitionToDozeAoD_whenDocked_requestPulse() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
- mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE_AOD);
-
- TestableLooper.get(this).processAllMessages();
-
- verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
- }
-
- @Test
- public void testTransitionToDoze_whenDockedHide_neverRequestPulse() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
- mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
-
- verify(mMachine, never()).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
- }
-
- @Test
- public void testTransitionToDozeAoD_whenDockedHide_requestDoze() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
+ public void onEvent_noneWhileDisabledAod_requestsDozeState() {
+ doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
- mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_AOD);
+ mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
verify(mMachine).requestState(eq(State.DOZE));
}
@Test
- public void testTransitionToPulsing_whenDockedHide_requestPulseOut() {
- mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
- when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
+ public void onEvent_hide_requestsDozeState() {
mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
- mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_PULSING);
-
- verify(mHost).stopPulsing();
+ verify(mMachine).requestState(eq(State.DOZE));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index bbd2ab12099f..0723a4ce74a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
@@ -45,6 +46,7 @@ import android.testing.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -66,6 +68,7 @@ public class DozeMachineTest extends SysuiTestCase {
private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock
private DozeLog mDozeLog;
+ @Mock private DockManager mDockManager;
private DozeServiceFake mServiceFake;
private WakeLockFake mWakeLockFake;
private AmbientDisplayConfiguration mConfigMock;
@@ -78,9 +81,11 @@ public class DozeMachineTest extends SysuiTestCase {
mWakeLockFake = new WakeLockFake();
mConfigMock = mock(AmbientDisplayConfiguration.class);
mPartMock = mock(DozeMachine.Part.class);
+ when(mDockManager.isDocked()).thenReturn(false);
+ when(mDockManager.isHidden()).thenReturn(false);
mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
- mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog);
+ mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager);
mMachine.setParts(new DozeMachine.Part[]{mPartMock});
}
@@ -112,6 +117,28 @@ public class DozeMachineTest extends SysuiTestCase {
}
@Test
+ public void testInitialize_afterDocked_goesToDockedAod() {
+ when(mDockManager.isDocked()).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+ assertEquals(DOZE_AOD_DOCKED, mMachine.getState());
+ }
+
+ @Test
+ public void testInitialize_afterDockPaused_goesToDoze() {
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+ when(mDockManager.isHidden()).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testPulseDone_goesToDoze() {
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
mMachine.requestState(INITIALIZED);
@@ -138,6 +165,34 @@ public class DozeMachineTest extends SysuiTestCase {
}
@Test
+ public void testPulseDone_afterDocked_goesToDockedAoD() {
+ when(mDockManager.isDocked()).thenReturn(true);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+
+ mMachine.requestState(DOZE_PULSE_DONE);
+
+ verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE_AOD_DOCKED);
+ assertEquals(DOZE_AOD_DOCKED, mMachine.getState());
+ }
+
+ @Test
+ public void testPulseDone_afterDockPaused_goesToDoze() {
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+ when(mDockManager.isHidden()).thenReturn(true);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+
+ mMachine.requestState(DOZE_PULSE_DONE);
+
+ verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testFinished_staysFinished() {
mMachine.requestState(INITIALIZED);
mMachine.requestState(FINISH);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 2ed0b4ffa0f4..399f723f4d62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
@@ -172,6 +173,16 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
+ public void testDockedAod_usesLightSensor() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+
+ mSensor.sendSensorEvent(3);
+
+ assertEquals(3, mServiceFake.screenBrightness);
+ }
+
+ @Test
public void testDozingAfterPulsing_pausesLightSensor() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index b92f173e8002..e8a3c0ec2e98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
@@ -128,6 +129,14 @@ public class DozeScreenStateTest extends SysuiTestCase {
}
@Test
+ public void testScreen_onInDockedAod() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+
+ assertEquals(Display.STATE_ON, mServiceFake.screenState);
+ }
+
+ @Test
public void test_initialScreenStatePostedToHandler() {
mHandlerFake.setMode(QUEUEING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 226bf6b3abce..bf1060905f10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -69,10 +69,11 @@ public class DozeTriggersTest extends SysuiTestCase {
private AlarmManager mAlarmManager;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private DockManager mDockManager;
private DozeTriggers mTriggers;
private FakeSensorManager mSensors;
private Sensor mTapSensor;
- private DockManager mDockManagerFake;
private FakeProximitySensor mProximitySensor;
@Before
@@ -83,14 +84,13 @@ public class DozeTriggersTest extends SysuiTestCase {
mSensors = spy(new FakeSensorManager(mContext));
mTapSensor = mSensors.getFakeTapSensor().getSensor();
WakeLock wakeLock = new WakeLockFake();
- mDockManagerFake = mock(DockManager.class);
AsyncSensorManager asyncSensorManager =
new AsyncSensorManager(mSensors, null, new Handler());
mProximitySensor = new FakeProximitySensor(getContext().getResources(), asyncSensorManager);
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
- mDockManagerFake, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
+ mDockManager, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
waitForSensorManager();
}
@@ -142,12 +142,24 @@ public class DozeTriggersTest extends SysuiTestCase {
}
@Test
+ public void transitionToDockedAod_disablesTouchSensors() {
+ mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+ waitForSensorManager();
+ verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+
+ mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.DOZE_AOD_DOCKED);
+ waitForSensorManager();
+
+ verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor));
+ }
+
+ @Test
public void testDockEventListener_registerAndUnregister() {
mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- verify(mDockManagerFake).addListener(any());
+ verify(mDockManager).addListener(any());
mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
- verify(mDockManagerFake).removeListener(any());
+ verify(mDockManager).removeListener(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 86869bd65900..2f53a01b1d69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -37,7 +37,6 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import org.junit.Before;
import org.junit.Test;
@@ -54,7 +53,6 @@ public class NotificationListenerTest extends SysuiTestCase {
@Mock private NotificationPresenter mPresenter;
@Mock private NotificationListenerService.RankingMap mRanking;
- @Mock private NotificationData mNotificationData;
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@@ -74,8 +72,6 @@ public class NotificationListenerTest extends SysuiTestCase {
new Handler(TestableLooper.get(this).getLooper()));
mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
mListener = new NotificationListener(mContext);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
@@ -90,7 +86,7 @@ public class NotificationListenerTest extends SysuiTestCase {
@Test
public void testNotificationUpdateCallsUpdateNotification() {
- when(mNotificationData.get(mSbn.getKey()))
+ when(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()))
.thenReturn(
new NotificationEntryBuilder()
.setSbn(mSbn)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 548f7a86adf3..d54e24ba2602 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.content.Intent.ACTION_USER_SWITCHED;
import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
@@ -24,7 +25,6 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -49,7 +49,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -72,7 +71,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
- @Mock private NotificationData mNotificationData;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private StatusBarKeyguardViewManager mKeyguardViewManager;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@@ -93,7 +91,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList(
new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0)));
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
Handler.createAsync(Looper.myLooper()));
@@ -170,9 +167,10 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
- when(mNotificationData.isHighPriority(any())).thenReturn(false);
- NotificationEntry entry = new NotificationEntryBuilder().build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_LOW)
+ .build();
entry.setBucket(BUCKET_SILENT);
assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
@@ -186,10 +184,12 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
- when(mNotificationData.isHighPriority(any())).thenReturn(false);
- NotificationEntry entry = new NotificationEntryBuilder().build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_LOW)
+ .build();
entry.setBucket(BUCKET_SILENT);
+ entry.setIsHighPriority(true);
assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 90bd0e9936be..88546b9b31a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.Instrumentation;
import android.app.Notification;
import android.app.Notification.BubbleMetadata;
import android.app.NotificationChannel;
@@ -40,8 +39,6 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
-import androidx.test.InstrumentationRegistry;
-
import com.android.systemui.TestableDependency;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubblesTestActivity;
@@ -72,7 +69,6 @@ public class NotificationTestHelper {
private static final String GROUP_KEY = "gruKey";
private final Context mContext;
- private final Instrumentation mInstrumentation;
private int mId;
private final NotificationGroupManager mGroupManager;
private ExpandableNotificationRow mRow;
@@ -83,7 +79,7 @@ public class NotificationTestHelper {
dependency.injectMockDependency(NotificationMediaManager.class);
dependency.injectMockDependency(BubbleController.class);
dependency.injectMockDependency(StatusBarWindowController.class);
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ dependency.injectMockDependency(SmartReplyController.class);
StatusBarStateController stateController = mock(StatusBarStateController.class);
mGroupManager = new NotificationGroupManager(stateController);
mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController,
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 18649bfe68d3..99c94ac7dec2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -46,7 +46,6 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -73,7 +72,6 @@ import java.util.List;
@TestableLooper.RunWithLooper
public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Mock private NotificationPresenter mPresenter;
- @Mock private NotificationData mNotificationData;
@Spy private FakeListContainer mListContainer = new FakeListContainer();
// Dependency mocks:
@@ -105,8 +103,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mHelper = new NotificationTestHelper(mContext, mDependency);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
mock(StatusBarStateControllerImpl.class), mEntryManager,
@@ -139,7 +135,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mListContainer.addContainerView(entry0.getRow());
mListContainer.addContainerView(entry1.getRow());
mListContainer.addContainerView(entry2.getRow());
- when(mNotificationData.getActiveNotifications()).thenReturn(
+ when(mEntryManager.getVisibleNotifications()).thenReturn(
Lists.newArrayList(entry0, entry1, entry2));
// Set up group manager to report that they should be bundled now.
@@ -168,7 +164,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
// Set up the prior state to look like one top level notification.
mListContainer.addContainerView(entry0.getRow());
- when(mNotificationData.getActiveNotifications()).thenReturn(
+ when(mEntryManager.getVisibleNotifications()).thenReturn(
Lists.newArrayList(entry0, entry1, entry2));
// Set up group manager to report that they should not be bundled now.
@@ -197,7 +193,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
// Set up the prior state to look like a top level notification.
mListContainer.addContainerView(entry0.getRow());
- when(mNotificationData.getActiveNotifications()).thenReturn(
+ when(mEntryManager.getVisibleNotifications()).thenReturn(
Lists.newArrayList(entry0, entry1));
// Set up group manager to report a suppressed summary now.
@@ -219,7 +215,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
public void testUpdateNotificationViews_appOps() throws Exception {
NotificationEntry entry0 = createEntry();
entry0.setRow(spy(entry0.getRow()));
- when(mNotificationData.getActiveNotifications()).thenReturn(
+ when(mEntryManager.getVisibleNotifications()).thenReturn(
Lists.newArrayList(entry0));
mListContainer.addContainerView(entry0.getRow());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index 820f4652e685..d003b994f6dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -175,6 +175,11 @@ public class RankingBuilder {
return this;
}
+ public RankingBuilder setVisuallyInterruptive(boolean interruptive) {
+ mIsVisuallyInterruptive = interruptive;
+ return this;
+ }
+
public RankingBuilder setImportance(@Importance int importance) {
mImportance = importance;
return this;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 9bc962c77019..fe117fe443a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -33,6 +33,7 @@ public class SbnBuilder {
private int mUid;
private int mInitialPid;
private Notification mNotification = new Notification();
+ private Notification.BubbleMetadata mBubbleMetadata;
private UserHandle mUser = UserHandle.of(0);
private String mOverrideGroupKey;
private long mPostTime;
@@ -54,6 +55,9 @@ public class SbnBuilder {
}
public StatusBarNotification build() {
+ if (mBubbleMetadata != null) {
+ mNotification.setBubbleMetadata(mBubbleMetadata);
+ }
return new StatusBarNotification(
mPkg,
mOpPkg,
@@ -116,4 +120,9 @@ public class SbnBuilder {
mPostTime = postTime;
return this;
}
+
+ public SbnBuilder setBubbleMetadata(Notification.BubbleMetadata data) {
+ mBubbleMetadata = data;
+ return this;
+ }
}
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 86ef6e8593fc..a98945f49b99 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
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
@@ -28,7 +29,6 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -40,14 +40,15 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.Notification;
-import android.app.NotificationManager;
+import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -73,18 +74,18 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
+import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -93,6 +94,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -104,13 +106,14 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper()
public class NotificationEntryManagerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
@@ -123,7 +126,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private NotificationRemoveInterceptor mRemoveInterceptor;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotificationListenerService.RankingMap mRankingMap;
+ @Mock private RankingMap mRankingMap;
@Mock private RemoteInputController mRemoteInputController;
// Dependency mocks:
@@ -139,6 +142,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private SmartReplyController mSmartReplyController;
@Mock private RowInflaterTask mAsyncInflationTask;
@Mock private NotificationRowBinder mMockedRowBinder;
+ @Mock private NotifLog mNotifLog;
private int mId;
private NotificationEntry mEntry;
@@ -146,43 +150,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
private TestableNotificationEntryManager mEntryManager;
private CountDownLatch mCountDownLatch;
- private class TestableNotificationEntryManager extends NotificationEntryManager {
- private final CountDownLatch mCountDownLatch;
-
- TestableNotificationEntryManager() {
- super(
- new NotificationData(
- mock(NotificationSectionsFeatureManager.class),
- mock(NotifLog.class),
- mock(PeopleNotificationIdentifier.class)),
- mock(NotifLog.class));
- mCountDownLatch = new CountDownLatch(1);
- }
-
- public void setNotificationData(NotificationData data) {
- mNotificationData = data;
- }
-
- @Override
- public void onAsyncInflationFinished(NotificationEntry entry,
- @InflationFlag int inflatedFlags) {
- super.onAsyncInflationFinished(entry, inflatedFlags);
-
- mCountDownLatch.countDown();
- }
-
- public CountDownLatch getCountDownLatch() {
- return mCountDownLatch;
- }
-
- public ArrayList<NotificationLifetimeExtender> getLifetimeExtenders() {
- return mNotificationLifetimeExtenders;
- }
- }
-
private void setUserSentiment(String key, int sentiment) {
doAnswer(invocationOnMock -> {
- NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+ Ranking ranking = (Ranking)
invocationOnMock.getArguments()[1];
ranking.populate(
key,
@@ -190,16 +160,16 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
false,
0,
0,
- NotificationManager.IMPORTANCE_DEFAULT,
+ IMPORTANCE_DEFAULT,
null, null,
null, null, null, true, sentiment, false, -1, false, null, null, false, false);
return true;
- }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
+ }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
}
private void setSmartActions(String key, ArrayList<Notification.Action> smartActions) {
doAnswer(invocationOnMock -> {
- NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+ Ranking ranking = (Ranking)
invocationOnMock.getArguments()[1];
ranking.populate(
key,
@@ -207,13 +177,13 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
false,
0,
0,
- NotificationManager.IMPORTANCE_DEFAULT,
+ IMPORTANCE_DEFAULT,
null, null,
null, null, null, true,
- NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
+ Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
false, smartActions, null, false, false);
return true;
- }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
+ }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
}
@Before
@@ -249,7 +219,18 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry.expandedIcon = mock(StatusBarIconView.class);
- mEntryManager = new TestableNotificationEntryManager();
+ mEntryManager = new TestableNotificationEntryManager(
+ mNotifLog,
+ mGroupManager,
+ new NotificationRankingManager(
+ () -> mock(NotificationMediaManager.class),
+ mGroupManager,
+ mHeadsUpManager,
+ mock(NotificationFilter.class),
+ mNotifLog,
+ mock(NotificationSectionsFeatureManager.class)),
+ mEnvironment
+ );
Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -258,19 +239,19 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
NotificationRowBinderImpl notificationRowBinder =
new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
mock(KeyguardBypassController.class),
- mock(StatusBarStateController.class));
+ mock(StatusBarStateController.class),
+ mock(NotificationLogger.class));
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
mEntryManager.setRowBinder(notificationRowBinder);
setUserSentiment(
- mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
+ mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
}
@Test
public void testAddNotification() throws Exception {
- com.android.systemui.util.Assert.isNotMainThread();
TestableLooper.get(this).processAllMessages();
doAnswer(invocation -> {
@@ -299,21 +280,20 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(mEntryListener).onNotificationAdded(entry);
verify(mPresenter).updateNotificationViews();
- assertEquals(mEntryManager.getNotificationData().get(mSbn.getKey()), entry);
+ assertEquals(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()), entry);
assertNotNull(entry.getRow());
assertEquals(mEntry.getUserSentiment(),
- NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
+ Ranking.USER_SENTIMENT_NEUTRAL);
}
@Test
public void testUpdateNotification() throws Exception {
- com.android.systemui.util.Assert.isNotMainThread();
TestableLooper.get(this).processAllMessages();
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
setUserSentiment(
- mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+ mEntry.getKey(), Ranking.USER_SENTIMENT_NEGATIVE);
mEntryManager.updateNotification(mSbn, mRankingMap);
TestableLooper.get(this).processMessages(1);
@@ -327,19 +307,15 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(mEntryListener).onPostEntryUpdated(mEntry);
assertNotNull(mEntry.getRow());
- assertEquals(mEntry.getUserSentiment(),
- NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+ assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
+ mEntry.getUserSentiment());
}
@Test
public void testUpdateNotification_prePostEntryOrder() throws Exception {
- com.android.systemui.util.Assert.isNotMainThread();
TestableLooper.get(this).processAllMessages();
- NotificationData notifData = mock(NotificationData.class);
- when(notifData.get(mEntry.getKey())).thenReturn(mEntry);
-
- mEntryManager.setNotificationData(notifData);
+ mEntryManager.addActiveNotificationForTest(mEntry);
mEntryManager.updateNotification(mSbn, mRankingMap);
TestableLooper.get(this).processMessages(1);
@@ -349,9 +325,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(mEntryListener, never()).onInflationError(any(), any());
// Ensure that update callbacks happen in correct order
- InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener);
+ InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener);
order.verify(mEntryListener).onPreEntryUpdated(mEntry);
- order.verify(notifData).filterAndSort(anyString());
order.verify(mPresenter).updateNotificationViews();
order.verify(mEntryListener).onPostEntryUpdated(mEntry);
@@ -359,11 +334,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
@Test
- public void testRemoveNotification() throws Exception {
- com.android.systemui.util.Assert.isNotMainThread();
+ public void testRemoveNotification() {
+ // Row inflation happens off thread, so pretend that this test looper is main
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -374,12 +350,11 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
eq(mEntry), any(), eq(false) /* removedByUser */);
verify(mRow).setRemoved();
- assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+ assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
}
@Test
public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
- com.android.systemui.util.Assert.isNotMainThread();
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -388,8 +363,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
@Test
- public void testRemoveNotification_whilePending() throws InterruptedException {
- com.android.systemui.util.Assert.isNotMainThread();
+ public void testRemoveNotification_whilePending() {
mEntryManager.setRowBinder(mMockedRowBinder);
@@ -408,7 +382,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry.setRow(mRow);
mEntry.setInflationTask(mAsyncInflationTask);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
@@ -424,7 +398,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mEntry.setRow(mRow);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
setSmartActions(mEntry.getKey(), null);
mEntryManager.updateNotificationRanking(mRankingMap);
@@ -438,7 +412,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mEntry.setRow(null);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
@@ -466,7 +440,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() {
// GIVEN an entry manager with a notification
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN a lifetime extender that always tries to extend lifetime
NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
@@ -479,15 +453,18 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
// THEN the extender is asked to manage the lifetime
verify(extender).setShouldManageLifetime(mEntry, true);
// THEN the notification is retained
- assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+ assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false));
}
@Test
public void testLifetimeExtenders_whenRetentionEndsNotificationIsRemoved() {
+ // Row inflation happens off thread, so pretend that this test looper is main
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
// GIVEN an entry manager with a notification whose life has been extended
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender();
mEntryManager.addNotificationLifetimeExtender(extender);
mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -498,7 +475,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
extender.getCallback().onSafeToRemove(mEntry.getKey());
// THEN the notification is removed
- assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+ assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false));
}
@@ -506,7 +483,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() {
// GIVEN an entry manager with a notification whose life has been extended
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
when(extender.shouldExtendLifetime(mEntry)).thenReturn(true);
mEntryManager.addNotificationLifetimeExtender(extender);
@@ -523,7 +500,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() {
// GIVEN an entry manager with a notification
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN two lifetime extenders, the first which never extends and the second which
// always extends
@@ -554,15 +531,15 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
*/
@Test
public void testPerformRemoveNotification_removedEntry() {
- mEntryManager.getNotificationData().remove(mSbn.getKey(), null /* ranking */);
+ mEntryManager.removeNotification(mSbn.getKey(), null, 0);
mEntryManager.performRemoveNotification(mSbn, REASON_CANCEL);
}
@Test
- public void testRemoveInterceptor_interceptsDontGetRemoved() {
+ public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException {
// GIVEN an entry manager with a notification
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN interceptor that intercepts that entry
when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
@@ -572,16 +549,19 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
- assertNotNull(mEntryManager.getNotificationData().get(mEntry.getKey()));
+ assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener, never()).onEntryRemoved(eq(mEntry),
any(NotificationVisibility.class), anyBoolean());
}
@Test
public void testRemoveInterceptor_notInterceptedGetsRemoved() {
+ // Row inflation happens off thread, so pretend that this test looper is main
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
// GIVEN an entry manager with a notification
mEntryManager.setRowBinder(mMockedRowBinder);
- mEntryManager.getNotificationData().add(mEntry);
+ mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN interceptor that doesn't intercept
when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
@@ -591,7 +571,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
- assertNull(mEntryManager.getNotificationData().get(mEntry.getKey()));
+ assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry),
any(NotificationVisibility.class), anyBoolean());
}
@@ -612,6 +592,63 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
.build();
}
+ /* Tests annexed from NotificationDataTest go here */
+
+ @Test
+ public void testChannelIsSetWhenAdded() {
+ NotificationChannel nc = new NotificationChannel(
+ "testId",
+ "testName",
+ IMPORTANCE_DEFAULT);
+
+ Ranking r = new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setChannel(nc)
+ .build();
+
+ RankingMap rm = new RankingMap(new Ranking[] { r });
+
+ // GIVEN: a notification is added, and the ranking updated
+ mEntryManager.addActiveNotificationForTest(mEntry);
+ mEntryManager.updateRanking(rm, "testReason");
+
+ // THEN the notification entry better have a channel on it
+ assertEquals(
+ "Channel must be set when adding a notification",
+ nc.getName(),
+ mEntry.getChannel().getName());
+ }
+
+ @Test
+ public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
+ Notification.Builder n = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+
+ NotificationEntry e2 = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setId(mId++)
+ .setNotification(n.build())
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+
+ mEntryManager.addActiveNotificationForTest(mEntry);
+ mEntryManager.addActiveNotificationForTest(e2);
+
+ when(mEnvironment.isNotificationForCurrentProfiles(mEntry.getSbn())).thenReturn(false);
+ when(mEnvironment.isNotificationForCurrentProfiles(e2.getSbn())).thenReturn(true);
+
+ List<NotificationEntry> result = mEntryManager.getActiveNotificationsForCurrentUser();
+ assertEquals(result.size(), 1);
+ junit.framework.Assert.assertEquals(result.get(0), e2);
+ }
+
+ /* End annex */
+
private Notification.Action createAction() {
return new Notification.Action.Builder(
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index d85f2752a247..68730d12dee3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -44,7 +44,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -71,7 +71,7 @@ public class NotificationFilterTest extends SysuiTestCase {
@Mock
ForegroundServiceController mFsc;
@Mock
- NotificationData.KeyguardEnvironment mEnvironment;
+ KeyguardEnvironment mEnvironment;
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
private NotificationFilter mNotificationFilter;
@@ -96,7 +96,7 @@ public class NotificationFilterTest extends SysuiTestCase {
new NotificationGroupManager(mock(StatusBarStateController.class)));
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
- mDependency.injectTestDependency(NotificationData.KeyguardEnvironment.class, mEnvironment);
+ mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index cc56949d67f7..133d52b4f946 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -17,9 +17,7 @@
package com.android.systemui.statusbar.notification;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.Notification;
@@ -34,14 +32,10 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.Before;
import org.junit.Test;
@@ -67,13 +61,6 @@ public class NotificationListControllerTest extends SysuiTestCase {
private NotificationEntryListener mEntryListener;
private DeviceProvisionedListener mProvisionedListener;
- // TODO: Remove this once EntryManager no longer needs to be mocked
- private NotificationData mNotificationData =
- new NotificationData(
- new NotificationSectionsFeatureManager(new DeviceConfigProxyFake(), mContext),
- mock(NotifLog.class),
- mock(PeopleNotificationIdentifier.class));
-
private int mNextNotifId = 0;
@Before
@@ -81,8 +68,6 @@ public class NotificationListControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
mController = new NotificationListController(
mEntryManager,
mListContainer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
new file mode 100644
index 000000000000..34beefe9843b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+
+import java.util.concurrent.CountDownLatch
+
+/**
+ * Enable some test capabilities for NEM without making everything public on the base class
+ */
+class TestableNotificationEntryManager(
+ log: NotifLog,
+ gm: NotificationGroupManager,
+ rm: NotificationRankingManager,
+ ke: KeyguardEnvironment
+) : NotificationEntryManager(log, gm, rm, ke) {
+
+ public var countDownLatch: CountDownLatch = CountDownLatch(1)
+
+ override fun onAsyncInflationFinished(entry: NotificationEntry?, inflatedFlags: Int) {
+ super.onAsyncInflationFinished(entry, inflatedFlags)
+ countDownLatch.countDown()
+ }
+
+ fun setUpForTest(
+ presenter: NotificationPresenter?,
+ listContainer: NotificationListContainer?,
+ headsUpManager: HeadsUpManagerPhone?
+ ) {
+ super.setUpWithPresenter(presenter, listContainer, headsUpManager)
+ }
+
+ fun setActiveNotificationList(activeList: List<NotificationEntry>) {
+ mSortedAndFiltered.clear()
+ mSortedAndFiltered.addAll(activeList)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
deleted file mode 100644
index 1a469d881d2c..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.collection;
-
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SbnBuilder;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
-
-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.HashMap;
-import java.util.Map;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationDataTest extends SysuiTestCase {
-
- private static final int UID_NORMAL = 123;
- private static final int UID_ALLOW_DURING_SETUP = 456;
- private static final NotificationChannel NOTIFICATION_CHANNEL =
- new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
-
- private NotificationEntry mEntry;
-
- @Mock
- ForegroundServiceController mFsc;
- @Mock
- NotificationData.KeyguardEnvironment mEnvironment;
-
- private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
- private TestableNotificationData mNotificationData;
- private ExpandableNotificationRow mRow;
-
- @Before
- public void setUp() throws Exception {
- com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
- MockitoAnnotations.initMocks(this);
-
- mEntry = new NotificationEntryBuilder()
- .setUid(UID_NORMAL)
- .build();
-
- when(mMockPackageManager.checkUidPermission(
- eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
- eq(UID_NORMAL)))
- .thenReturn(PackageManager.PERMISSION_DENIED);
- when(mMockPackageManager.checkUidPermission(
- eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
- eq(UID_ALLOW_DURING_SETUP)))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
-
- mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
- mDependency.injectTestDependency(NotificationGroupManager.class,
- new NotificationGroupManager(mock(StatusBarStateController.class)));
- mDependency.injectMockDependency(ShadeController.class);
- mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
- mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
- when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
- when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
- mNotificationData = new TestableNotificationData(
- mock(NotificationSectionsFeatureManager.class));
- mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class), "");
- mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
- Dependency.get(InitController.class).executePostInitTasks();
- }
-
- @Test
- public void testChannelSetWhenAdded() {
- Bundle override = new Bundle();
- override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
- mNotificationData.rankingOverrides.put(mRow.getEntry().getKey(), override);
- mNotificationData.add(mRow.getEntry());
- assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().getChannel());
- }
-
- @Test
- public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
- throws Exception {
- mNotificationData.add(mRow.getEntry());
- ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency)
- .createRow();
- mNotificationData.add(row2.getEntry());
-
- when(mEnvironment.isNotificationForCurrentProfiles(
- mRow.getEntry().getSbn())).thenReturn(false);
- when(mEnvironment.isNotificationForCurrentProfiles(
- row2.getEntry().getSbn())).thenReturn(true);
- ArrayList<NotificationEntry> result =
- mNotificationData.getNotificationsForCurrentUser();
-
- assertEquals(result.size(), 1);
- junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
- }
-
- @Test
- public void testIsExemptFromDndVisualSuppression_foreground() {
- initStatusBarNotification(false);
-
- mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- mEntry.setRow(mRow);
- mNotificationData.add(mEntry);
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_VIS_EFFECTS, 255);
- mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
- assertTrue(mEntry.isExemptFromDndVisualSuppression());
- assertFalse(mEntry.shouldSuppressAmbient());
- }
-
- @Test
- public void testIsExemptFromDndVisualSuppression_media() {
- initStatusBarNotification(false);
- Notification n = mEntry.getSbn().getNotification();
- Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
- nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
- n = nb.build();
- modifySbn(mEntry)
- .setNotification(n)
- .build();
- mEntry.setRow(mRow);
- mNotificationData.add(mEntry);
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_VIS_EFFECTS, 255);
- mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
- assertTrue(mEntry.isExemptFromDndVisualSuppression());
- assertFalse(mEntry.shouldSuppressAmbient());
- }
-
- @Test
- public void testIsExemptFromDndVisualSuppression_system() {
- initStatusBarNotification(false);
- mEntry.setRow(mRow);
- mEntry.mIsSystemNotification = true;
- mNotificationData.add(mEntry);
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_VIS_EFFECTS, 255);
- mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
- assertTrue(mEntry.isExemptFromDndVisualSuppression());
- assertFalse(mEntry.shouldSuppressAmbient());
- }
-
- @Test
- public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
- initStatusBarNotification(false);
- NotificationEntry entry = new NotificationEntryBuilder()
- .setUid(UID_NORMAL)
- .build();
- entry.setRow(mRow);
- entry.mIsSystemNotification = true;
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
- mNotificationData.rankingOverrides.put(entry.getKey(), override);
- mNotificationData.add(entry);
-
- modifySbn(entry)
- .setNotification(
- new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build())
- .build();
- assertFalse(entry.isExemptFromDndVisualSuppression());
- assertTrue(entry.shouldSuppressAmbient());
-
- modifySbn(entry)
- .setNotification(
- new Notification.Builder(mContext, "")
- .setCategory(CATEGORY_REMINDER)
- .build())
- .build();
- assertFalse(entry.isExemptFromDndVisualSuppression());
-
- modifySbn(entry)
- .setNotification(
- new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build())
- .build();
- assertFalse(entry.isExemptFromDndVisualSuppression());
-
- modifySbn(entry)
- .setNotification(
- new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build())
- .build();
- assertFalse(entry.isExemptFromDndVisualSuppression());
-
- modifySbn(entry)
- .setNotification(
- new Notification.Builder(mContext, "")
- .setCategory(CATEGORY_MESSAGE)
- .build())
- .build();
- assertFalse(entry.isExemptFromDndVisualSuppression());
- }
-
- @Test
- public void testCreateNotificationDataEntry_RankingUpdate() {
- StatusBarNotification sbn = new SbnBuilder().build();
- sbn.getNotification().actions =
- new Notification.Action[] { createContextualAction("appGeneratedAction") };
-
- ArrayList<Notification.Action> systemGeneratedSmartActions =
- createActions("systemGeneratedAction");
-
- SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
- ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
- snoozeCriterions.add(snoozeCriterion);
-
- Ranking ranking = new RankingBuilder()
- .setKey(sbn.getKey())
- .setSmartActions(systemGeneratedSmartActions)
- .setChannel(NOTIFICATION_CHANNEL)
- .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
- .setSnoozeCriteria(snoozeCriterions)
- .build();
-
- NotificationEntry entry =
- new NotificationEntry(sbn, ranking);
-
- assertEquals(systemGeneratedSmartActions, entry.getSmartActions());
- assertEquals(NOTIFICATION_CHANNEL, entry.getChannel());
- assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment());
- assertEquals(snoozeCriterions, entry.getSnoozeCriteria());
- }
-
- @Test
- public void notificationDataEntry_testIsLastMessageFromReply() {
- Person.Builder person = new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true);
-
- // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
- Bundle bundle = new Bundle();
- bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
- Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
- "text", 0, person.build()).toBundle() };
- bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
-
- Notification notification = new Notification.Builder(mContext, "test")
- .addExtras(bundle)
- .build();
-
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("pkg")
- .setOpPkg("pkg")
- .setTag("tag")
- .setNotification(notification)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
- entry.setHasSentReply();
-
- assertTrue(entry.isLastMessageFromReply());
- }
-
- @Test
- public void personHighPriority() {
- Person person = new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build();
-
- Notification notification = new Notification.Builder(mContext, "test")
- .addPerson(person)
- .build();
-
- StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notification, mContext.getUser(), "", 0);
-
- assertTrue(mNotificationData.isHighPriority(sbn));
- }
-
- @Test
- public void messagingStyleHighPriority() {
-
- Notification notification = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
-
- StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notification, mContext.getUser(), "", 0);
-
- assertTrue(mNotificationData.isHighPriority(sbn));
- }
-
- @Test
- public void minForegroundNotHighPriority() {
- Notification notification = mock(Notification.class);
- when(notification.isForegroundService()).thenReturn(true);
-
- StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notification, mContext.getUser(), "", 0);
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
- mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
- assertFalse(mNotificationData.isHighPriority(sbn));
- }
-
- @Test
- public void lowForegroundHighPriority() {
- Notification notification = mock(Notification.class);
- when(notification.isForegroundService()).thenReturn(true);
-
- StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notification, mContext.getUser(), "", 0);
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
- assertTrue(mNotificationData.isHighPriority(sbn));
- }
-
- @Test
- public void userChangeTrumpsHighPriorityCharacteristics() {
- Person person = new Person.Builder()
- .setName("name")
- .setKey("abc")
- .setUri("uri")
- .setBot(true)
- .build();
-
- Notification notification = new Notification.Builder(mContext, "test")
- .addPerson(person)
- .setStyle(new Notification.MessagingStyle(""))
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
- .build();
-
- StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
- notification, mContext.getUser(), "", 0);
-
- NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
- channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-
- Bundle override = new Bundle();
- override.putParcelable(OVERRIDE_CHANNEL, channel);
- mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
- assertFalse(mNotificationData.isHighPriority(sbn));
- }
-
- @Test
- public void testSort_highPriorityTrumpsNMSRank() {
- // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
- // front
- Notification aN = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
- NotificationEntry a = new NotificationEntryBuilder()
- .setPkg("pkg")
- .setOpPkg("pkg")
- .setTag("tag")
- .setNotification(aN)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
- a.setRow(mock(ExpandableNotificationRow.class));
- a.setIsHighPriority(false);
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- override.putInt(OVERRIDE_RANK, 1);
- mNotificationData.rankingOverrides.put(a.getKey(), override);
-
- Notification bN = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
- NotificationEntry b = new NotificationEntryBuilder()
- .setPkg("pkg2")
- .setOpPkg("pkg2")
- .setTag("tag")
- .setNotification(bN)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
- b.setIsHighPriority(true);
- b.setRow(mock(ExpandableNotificationRow.class));
-
- Bundle bOverride = new Bundle();
- bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- bOverride.putInt(OVERRIDE_RANK, 2);
- mNotificationData.rankingOverrides.put(b.getKey(), bOverride);
-
- assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
- }
-
- @Test
- public void testSort_samePriorityUsesNMSRank() {
- // NMS rank says A and then B, and they are the same priority so use that rank
- Notification aN = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
- NotificationEntry a = new NotificationEntryBuilder()
- .setPkg("pkg")
- .setOpPkg("pkg")
- .setTag("tag")
- .setNotification(aN)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
- a.setRow(mock(ExpandableNotificationRow.class));
- a.setIsHighPriority(false);
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- override.putInt(OVERRIDE_RANK, 1);
- mNotificationData.rankingOverrides.put(a.getKey(), override);
-
- Notification bN = new Notification.Builder(mContext, "test")
- .setStyle(new Notification.MessagingStyle(""))
- .build();
- NotificationEntry b = new NotificationEntryBuilder()
- .setPkg("pkg2")
- .setOpPkg("pkg2")
- .setTag("tag")
- .setNotification(bN)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
- b.setRow(mock(ExpandableNotificationRow.class));
- b.setIsHighPriority(false);
-
- Bundle bOverride = new Bundle();
- bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- bOverride.putInt(OVERRIDE_RANK, 2);
- mNotificationData.rankingOverrides.put(b.getKey(), bOverride);
-
- assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
- }
-
- @Test
- public void testSort_properlySetsAlertingBucket() {
- Notification notification = new Notification.Builder(mContext, "test")
- .build();
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("pkg")
- .setOpPkg("pkg")
- .setTag("tag")
- .setNotification(notification)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
- mNotificationData.rankingOverrides.put(entry.getKey(), override);
-
- entry.setRow(mRow);
- mNotificationData.add(entry);
-
- assertEquals(entry.getBucket(), BUCKET_ALERTING);
- }
-
- @Test
- public void testSort_properlySetsSilentBucket() {
- Notification notification = new Notification.Builder(mContext, "test")
- .build();
-
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("pkg")
- .setOpPkg("pkg")
- .setTag("tag")
- .setNotification(notification)
- .setUser(mContext.getUser())
- .setOverrideGroupKey("")
- .build();
-
- Bundle override = new Bundle();
- override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
- mNotificationData.rankingOverrides.put(entry.getKey(), override);
-
- entry.setRow(mRow);
- mNotificationData.add(entry);
-
- assertEquals(entry.getBucket(), BUCKET_SILENT);
- }
-
- private void initStatusBarNotification(boolean allowDuringSetup) {
- Bundle bundle = new Bundle();
- bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
- Notification notification = new Notification.Builder(mContext, "test")
- .addExtras(bundle)
- .build();
- modifySbn(mEntry)
- .setNotification(notification)
- .build();
- }
-
- public static class TestableNotificationData extends NotificationData {
- public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
- super(
- sectionsFeatureManager,
- mock(NotifLog.class),
- mock(PeopleNotificationIdentifier.class));
- }
-
- public static final String OVERRIDE_RANK = "r";
- public static final String OVERRIDE_DND = "dnd";
- public static final String OVERRIDE_VIS_OVERRIDE = "vo";
- public static final String OVERRIDE_VIS_EFFECTS = "ve";
- public static final String OVERRIDE_IMPORTANCE = "i";
- public static final String OVERRIDE_IMP_EXP = "ie";
- public static final String OVERRIDE_GROUP = "g";
- public static final String OVERRIDE_CHANNEL = "c";
- public static final String OVERRIDE_PEOPLE = "p";
- public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
- public static final String OVERRIDE_BADGE = "b";
- public static final String OVERRIDE_USER_SENTIMENT = "us";
- public static final String OVERRIDE_HIDDEN = "h";
- public static final String OVERRIDE_LAST_ALERTED = "la";
- public static final String OVERRIDE_NOISY = "n";
- public static final String OVERRIDE_SMART_ACTIONS = "sa";
- public static final String OVERRIDE_SMART_REPLIES = "sr";
- public static final String OVERRIDE_BUBBLE = "cb";
- public static final String OVERRIDE_VISUALLY_INTERRUPTIVE = "vi";
-
- public Map<String, Bundle> rankingOverrides = new HashMap<>();
-
- @Override
- protected boolean getRanking(String key, Ranking outRanking) {
- super.getRanking(key, outRanking);
-
- ArrayList<String> currentAdditionalPeople = new ArrayList<>();
- if (outRanking.getAdditionalPeople() != null) {
- currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
- }
-
- ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
- if (outRanking.getSnoozeCriteria() != null) {
- currentSnooze.addAll(outRanking.getSnoozeCriteria());
- }
-
- ArrayList<Notification.Action> currentActions = new ArrayList<>();
- if (outRanking.getSmartActions() != null) {
- currentActions.addAll(outRanking.getSmartActions());
- }
-
- ArrayList<CharSequence> currentReplies = new ArrayList<>();
- if (outRanking.getSmartReplies() != null) {
- currentReplies.addAll(outRanking.getSmartReplies());
- }
-
- if (rankingOverrides.get(key) != null) {
- Bundle overrides = rankingOverrides.get(key);
- outRanking.populate(key,
- overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
- overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
- overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
- overrides.getInt(OVERRIDE_VIS_EFFECTS,
- outRanking.getSuppressedVisualEffects()),
- overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
- overrides.getCharSequence(OVERRIDE_IMP_EXP,
- outRanking.getImportanceExplanation()),
- overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
- overrides.containsKey(OVERRIDE_CHANNEL)
- ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
- : outRanking.getChannel(),
- overrides.containsKey(OVERRIDE_PEOPLE)
- ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
- : currentAdditionalPeople,
- overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
- ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
- : currentSnooze,
- overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
- overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
- overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
- overrides.getLong(OVERRIDE_LAST_ALERTED,
- outRanking.getLastAudiblyAlertedMillis()),
- overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
- overrides.containsKey(OVERRIDE_SMART_ACTIONS)
- ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
- : currentActions,
- overrides.containsKey(OVERRIDE_SMART_REPLIES)
- ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
- : currentReplies,
- overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()),
- overrides.getBoolean(OVERRIDE_VISUALLY_INTERRUPTIVE,
- outRanking.visuallyInterruptive()));
- } else {
- outRanking.populate(
- new RankingBuilder()
- .setKey(key)
- .build());
- }
- return true;
- }
- }
-
- private Notification.Action createContextualAction(String title) {
- return new Notification.Action.Builder(
- Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
- title,
- PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
- .setContextual(true)
- .build();
- }
-
- private Notification.Action createAction(String title) {
- return new Notification.Action.Builder(
- Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
- title,
- PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
- }
-
- private ArrayList<Notification.Action> createActions(String... titles) {
- ArrayList<Notification.Action> actions = new ArrayList<>();
- for (String title : titles) {
- actions.add(createAction(title));
- }
- return actions;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
new file mode 100644
index 000000000000..536aeb4d0163
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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 static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.SbnBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class NotificationEntryTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+ private static final int UID_NORMAL = 123;
+ private static final NotificationChannel NOTIFICATION_CHANNEL =
+ new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
+
+ private int mId;
+
+ private NotificationEntry mEntry;
+
+ @Before
+ public void setup() {
+ Notification.Builder n = new Notification.Builder(mContext, "")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+
+ mEntry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setId(mId++)
+ .setNotification(n.build())
+ .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .build();
+ }
+
+ @Test
+ public void testIsExemptFromDndVisualSuppression_foreground() {
+ mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+
+ assertTrue(mEntry.isExemptFromDndVisualSuppression());
+ assertFalse(mEntry.shouldSuppressAmbient());
+ }
+
+ @Test
+ public void testIsExemptFromDndVisualSuppression_media() {
+ Notification.Builder n = new Notification.Builder(mContext, "")
+ .setStyle(new Notification.MediaStyle()
+ .setMediaSession(mock(MediaSession.Token.class)))
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+ NotificationEntry e1 = new NotificationEntryBuilder()
+ .setNotification(n.build())
+ .build();
+
+ assertTrue(e1.isExemptFromDndVisualSuppression());
+ assertFalse(e1.shouldSuppressAmbient());
+ }
+
+ @Test
+ public void testIsExemptFromDndVisualSuppression_system() {
+ mEntry.mIsSystemNotification = true;
+
+ assertTrue(mEntry.isExemptFromDndVisualSuppression());
+ assertFalse(mEntry.shouldSuppressAmbient());
+ }
+
+ @Test
+ public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setUid(UID_NORMAL)
+ .build();
+ entry.mIsSystemNotification = true;
+ modifyRanking(entry).setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT).build();
+
+ modifySbn(entry)
+ .setNotification(
+ new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build())
+ .build();
+ assertFalse(entry.isExemptFromDndVisualSuppression());
+ assertTrue(entry.shouldSuppressAmbient());
+
+ modifySbn(entry)
+ .setNotification(
+ new Notification.Builder(mContext, "")
+ .setCategory(CATEGORY_REMINDER)
+ .build())
+ .build();
+ assertFalse(entry.isExemptFromDndVisualSuppression());
+
+ modifySbn(entry)
+ .setNotification(
+ new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build())
+ .build();
+ assertFalse(entry.isExemptFromDndVisualSuppression());
+
+ modifySbn(entry)
+ .setNotification(
+ new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build())
+ .build();
+ assertFalse(entry.isExemptFromDndVisualSuppression());
+
+ modifySbn(entry)
+ .setNotification(
+ new Notification.Builder(mContext, "")
+ .setCategory(CATEGORY_MESSAGE)
+ .build())
+ .build();
+ assertFalse(entry.isExemptFromDndVisualSuppression());
+ }
+
+ @Test
+ public void testCreateNotificationDataEntry_RankingUpdate() {
+ StatusBarNotification sbn = new SbnBuilder().build();
+ sbn.getNotification().actions =
+ new Notification.Action[]{createContextualAction("appGeneratedAction")};
+
+ ArrayList<Notification.Action> systemGeneratedSmartActions =
+ createActions("systemGeneratedAction");
+
+ SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
+ ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
+ snoozeCriterions.add(snoozeCriterion);
+
+ Ranking ranking = new RankingBuilder()
+ .setKey(sbn.getKey())
+ .setSmartActions(systemGeneratedSmartActions)
+ .setChannel(NOTIFICATION_CHANNEL)
+ .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
+ .setSnoozeCriteria(snoozeCriterions)
+ .build();
+
+ NotificationEntry entry =
+ new NotificationEntry(sbn, ranking);
+
+ assertEquals(systemGeneratedSmartActions, entry.getSmartActions());
+ assertEquals(NOTIFICATION_CHANNEL, entry.getChannel());
+ assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment());
+ assertEquals(snoozeCriterions, entry.getSnoozeCriteria());
+ }
+
+ @Test
+ public void notificationDataEntry_testIsLastMessageFromReply() {
+ Person.Builder person = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true);
+
+ // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
+ Bundle[] messagesBundle = new Bundle[]{new Notification.MessagingStyle.Message(
+ "text", 0, person.build()).toBundle()};
+ bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addExtras(bundle)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(notification)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build();
+ entry.setHasSentReply();
+
+ assertTrue(entry.isLastMessageFromReply());
+ }
+
+ private Notification.Action createContextualAction(String title) {
+ return new Notification.Action.Builder(
+ Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+ title,
+ PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
+ .setContextual(true)
+ .build();
+ }
+
+ private Notification.Action createAction(String title) {
+ return new Notification.Action.Builder(
+ Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+ title,
+ PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+ }
+
+ private ArrayList<Notification.Action> createActions(String... titles) {
+ ArrayList<Notification.Action> actions = new ArrayList<>();
+ for (String title : titles) {
+ actions.add(createAction(title));
+ }
+ return actions;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
new file mode 100644
index 000000000000..01b2f8932d9b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -0,0 +1,318 @@
+/*
+ * 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.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.Person
+import android.service.notification.NotificationListenerService.RankingMap
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+
+import org.junit.runner.RunWith
+
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationEntryBuilder
+import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationFilter
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import dagger.Lazy
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationRankingManagerTest
+ : SysuiTestCase() {
+
+ private var lazyMedia: Lazy<NotificationMediaManager> = Lazy {
+ mock<NotificationMediaManager>(NotificationMediaManager::class.java)
+ }
+
+ private val rankingManager = TestableNotificationRankingManager(
+ lazyMedia,
+ mock<NotificationGroupManager>(NotificationGroupManager::class.java),
+ mock<HeadsUpManager>(HeadsUpManager::class.java),
+ mock<NotificationFilter>(NotificationFilter::class.java),
+ mock<NotifLog>(NotifLog::class.java),
+ mock<NotificationSectionsFeatureManager>(NotificationSectionsFeatureManager::class.java)
+ )
+
+ @Before
+ fun setup() {
+ }
+
+ @Test
+ fun testPeopleNotification_isHighPriority() {
+ val person = Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true)
+ .build()
+
+ val notification = Notification.Builder(mContext, "test")
+ .addPerson(person)
+ .build()
+
+ val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.user, "", 0)
+
+ val e = NotificationEntryBuilder()
+ .setNotification(notification)
+ .setSbn(sbn)
+ .build()
+
+ assertTrue(rankingManager.isHighPriority2(e))
+ }
+
+ @Test
+ fun messagingStyleHighPriority() {
+
+ val notif = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+
+ val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notif, mContext.getUser(), "", 0)
+
+ val e = NotificationEntryBuilder()
+ .setNotification(notif)
+ .setSbn(sbn)
+ .build()
+
+ assertTrue(rankingManager.isHighPriority2(e))
+ }
+
+ @Test
+ fun lowForegroundHighPriority() {
+ val notification = mock(Notification::class.java)
+ `when`<Boolean>(notification.isForegroundService).thenReturn(true)
+
+ val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.user, "", 0)
+
+ val e = NotificationEntryBuilder()
+ .setNotification(notification)
+ .setSbn(sbn)
+ .build()
+
+ modifyRanking(e)
+ .setImportance(IMPORTANCE_LOW)
+ .build()
+
+ assertTrue(rankingManager.isHighPriority2(e))
+ }
+
+ @Test
+ fun userChangeTrumpsHighPriorityCharacteristics() {
+ val person = Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true)
+ .build()
+
+ val notification = Notification.Builder(mContext, "test")
+ .addPerson(person)
+ .setStyle(Notification.MessagingStyle(""))
+ .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .build()
+
+ val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.user, "", 0)
+
+ val channel = NotificationChannel("a", "a", IMPORTANCE_LOW)
+ channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE)
+
+ val e = NotificationEntryBuilder()
+ .setSbn(sbn)
+ .setChannel(channel)
+ .build()
+
+ assertFalse(rankingManager.isHighPriority2(e))
+ }
+
+ @Test
+ fun testSort_highPriorityTrumpsNMSRank() {
+ // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
+ // front
+ val aN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val a = NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(aN)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+
+ a.setIsHighPriority(false)
+
+ modifyRanking(a)
+ .setImportance(IMPORTANCE_LOW)
+ .setRank(1)
+ .build()
+
+ val bN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val b = NotificationEntryBuilder()
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(bN)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+ b.setIsHighPriority(true)
+
+ modifyRanking(b)
+ .setImportance(IMPORTANCE_LOW)
+ .setRank(2)
+ .build()
+
+ assertEquals(
+ listOf(b, a),
+ rankingManager.updateRanking(null, listOf(a, b), "test"))
+ }
+
+ @Test
+ fun testSort_samePriorityUsesNMSRank() {
+ // NMS rank says A and then B, and they are the same priority so use that rank
+ val aN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val a = NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(aN)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+ a.setIsHighPriority(false)
+
+ modifyRanking(a)
+ .setImportance(IMPORTANCE_LOW)
+ .setRank(1)
+ .build()
+
+ val bN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val b = NotificationEntryBuilder()
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(bN)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+ b.setIsHighPriority(false)
+
+ modifyRanking(b)
+ .setImportance(IMPORTANCE_LOW)
+ .setRank(2)
+ .build()
+
+ assertEquals(
+ listOf(a, b),
+ rankingManager.updateRanking(null, listOf(a, b), "test"))
+ }
+
+ @Test
+ fun testSort_properlySetsAlertingBucket() {
+ val notif = Notification.Builder(mContext, "test") .build()
+
+ val e = NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(notif)
+ .setUser(mContext.user)
+ .setOverrideGroupKey("")
+ .build()
+
+ modifyRanking(e).setImportance(IMPORTANCE_DEFAULT) .build()
+
+ rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
+ assertEquals(e.bucket, BUCKET_ALERTING)
+ }
+
+ @Test
+ fun testSort_properlySetsSilentBucket() {
+ val notif = Notification.Builder(mContext, "test") .build()
+
+ val e = NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(notif)
+ .setUser(mContext.user)
+ .setOverrideGroupKey("")
+ .build()
+
+ modifyRanking(e).setImportance(IMPORTANCE_LOW).build()
+
+ rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
+ assertEquals(e.bucket, BUCKET_SILENT)
+ }
+
+ internal class TestableNotificationRankingManager(
+ mediaManager: Lazy<NotificationMediaManager>,
+ groupManager: NotificationGroupManager,
+ headsUpManager: HeadsUpManager,
+ filter: NotificationFilter,
+ notifLog: NotifLog,
+ sectionsFeatureManager: NotificationSectionsFeatureManager
+ ) : NotificationRankingManager(
+ mediaManager,
+ groupManager,
+ headsUpManager,
+ filter,
+ notifLog,
+ sectionsFeatureManager
+ ) {
+
+ fun isHighPriority2(e: NotificationEntry): Boolean {
+ return isHighPriority(e)
+ }
+
+ fun applyTestRankingMap(r: RankingMap) {
+ rankingMap = r
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 47c17ad88fcb..d1398667f497 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -44,7 +44,6 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -71,7 +70,6 @@ public class NotificationLoggerTest extends SysuiTestCase {
@Mock private NotificationListContainer mListContainer;
@Mock private IStatusBarService mBarService;
- @Mock private NotificationData mNotificationData;
@Mock private ExpandableNotificationRow mRow;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@@ -91,8 +89,6 @@ public class NotificationLoggerTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(NotificationListener.class, mListener);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
mEntry = new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_NAME)
.setOpPkg(TEST_PACKAGE_NAME)
@@ -131,7 +127,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
any(NotificationVisibility[].class));
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
- when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
TestableLooper.get(this).processAllMessages();
waitForUiOffloadThread();
@@ -153,7 +149,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
public void testStoppingNotificationLoggingReportsCurrentNotifications()
throws Exception {
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
- when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
TestableLooper.get(this).processAllMessages();
waitForUiOffloadThread();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index bc616c5d7163..0b123fc8ff7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -321,6 +321,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
.build();
when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+ NotificationEntry entry = row.getEntry();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -331,7 +332,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
- eq(statusBarNotification),
+ eq(entry),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -352,6 +353,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
.build();
when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+ NotificationEntry entry = row.getEntry();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -362,7 +364,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
- eq(statusBarNotification),
+ eq(entry),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -385,6 +387,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
row.getEntry().setIsHighPriority(true);
when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+ NotificationEntry entry = row.getEntry();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -395,7 +398,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
- eq(statusBarNotification),
+ eq(entry),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -416,6 +419,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
.build();
when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+ NotificationEntry entry = row.getEntry();
+
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -427,7 +432,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
- eq(statusBarNotification),
+ eq(entry),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
@@ -448,6 +453,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
.build();
when(row.getIsNonblockable()).thenReturn(false);
StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+ NotificationEntry entry = row.getEntry();
mGutsManager.initializeNotificationInfo(row, notificationInfoView);
@@ -458,7 +464,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anySet(),
- eq(statusBarNotification),
+ eq(entry),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
any(NotificationInfo.OnAppSettingsClickListener.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 703adf7a047f..bdca7efeb608 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static android.app.Notification.FLAG_BUBBLE;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -49,10 +50,13 @@ import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.app.PendingIntent;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -72,7 +76,12 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.bubbles.BubblesTestActivity;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.After;
import org.junit.Before;
@@ -106,6 +115,9 @@ public class NotificationInfoTest extends SysuiTestCase {
private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>();
private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>();
private StatusBarNotification mSbn;
+ private NotificationEntry mEntry;
+ private StatusBarNotification mBubbleSbn;
+ private NotificationEntry mBubbleEntry;
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@@ -119,6 +131,8 @@ public class NotificationInfoTest extends SysuiTestCase {
private NotificationBlockingHelperManager mBlockingHelperManager;
@Mock
private VisualStabilityManager mVisualStabilityManager;
+ @Mock
+ private BubbleController mBubbleController;
@Before
public void setUp() throws Exception {
@@ -126,13 +140,18 @@ public class NotificationInfoTest extends SysuiTestCase {
NotificationBlockingHelperManager.class,
mBlockingHelperManager);
mTestableLooper = TestableLooper.get(this);
+
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+ mDependency.injectTestDependency(BubbleController.class, mBubbleController);
// Inflate the layout
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
null);
mNotificationInfo.setGutsParent(mock(NotificationGuts.class));
+ // Our view is never attached to a window so the View#post methods in NotificationInfo never
+ // get called. Setting this will skip the post and do the action immediately.
+ mNotificationInfo.mSkipPost = true;
// PackageManager must return a packageInfo and applicationInfo.
final PackageInfo packageInfo = new PackageInfo();
@@ -164,6 +183,16 @@ public class NotificationInfoTest extends SysuiTestCase {
mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
+ mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+
+ PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
+ new Intent(mContext, BubblesTestActivity.class), 0);
+ mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata(
+ new Notification.BubbleMetadata.Builder()
+ .setIntent(bubbleIntent)
+ .setIcon(Icon.createWithResource(mContext, R.drawable.android)).build())
+ .build();
+ mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build();
Settings.Secure.putInt(mContext.getContentResolver(),
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
@@ -182,17 +211,6 @@ public class NotificationInfoTest extends SysuiTestCase {
() -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
}
- private void ensureNoUndoButton() {
- PollingCheck.waitFor(1000,
- () -> GONE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility()
- && !mNotificationInfo.isAnimating());
- }
-
- private void waitForStopButton() {
- PollingCheck.waitFor(1000,
- () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
- }
-
@Test
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -203,7 +221,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -228,7 +246,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -249,7 +267,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -273,6 +291,7 @@ public class NotificationInfoTest extends SysuiTestCase {
applicationInfo);
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
+ NotificationEntry entry = new NotificationEntryBuilder().setSbn(mSbn).build();
mNotificationInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
@@ -280,7 +299,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ entry,
null,
null,
null,
@@ -304,7 +323,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -331,7 +350,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -353,7 +372,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -374,7 +393,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mDefaultNotificationChannel,
mDefaultNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -399,7 +418,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mDefaultNotificationChannel,
mDefaultNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -420,7 +439,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -441,7 +460,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
mock(NotificationInfo.OnSettingsClickListener.class),
null,
@@ -468,7 +487,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
@@ -495,7 +514,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -517,7 +536,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
@@ -540,7 +559,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -555,7 +574,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
(View v, NotificationChannel c, int appUid) -> { },
null,
@@ -576,7 +595,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -600,7 +619,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -625,7 +644,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -647,7 +666,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mVisualStabilityManager,
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
- mSbn,
+ mEntry,
null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
@@ -675,7 +694,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
- mSbn,
+ mEntry,
null,
null,
null,
@@ -698,7 +717,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
- mSbn,
+ mEntry,
null,
null,
null,
@@ -721,7 +740,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -738,6 +757,202 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
+ public void testBindNotification_alertIsSelected() throws Exception {
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+ assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
+ }
+
+ @Test
+ public void testBindNotification_silenceIsSelected() throws Exception {
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ false);
+ assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
+ }
+
+ @Test
+ public void testBindNotification_bubbleIsSelected() throws Exception {
+ mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+
+ View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+ assertEquals(View.VISIBLE, bubbleView.getVisibility());
+ assertTrue(bubbleView.isSelected());
+ }
+
+ @Test
+ public void testBindNotification_whenCanBubble() throws Exception {
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+
+ View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+ assertEquals(View.VISIBLE, bubbleView.getVisibility());
+ assertFalse(bubbleView.isSelected());
+ }
+
+ @Test
+ public void testBindNotification_whenCantBubble() throws Exception {
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+ View bubbleView = mNotificationInfo.findViewById(R.id.bubble);
+ assertEquals(View.GONE, bubbleView.getVisibility());
+ }
+
+ @Test
+ public void testBubble_promotesBubble() throws Exception {
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+
+ assertFalse(mBubbleEntry.isBubble());
+
+ // Promote it
+ mNotificationInfo.findViewById(R.id.bubble).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ verify(mBubbleController, times(1)).onUserCreatedBubbleFromNotification(mBubbleEntry);
+ }
+
+ @Test
+ public void testAlert_demotesBubble() throws Exception {
+ mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+
+ assertTrue(mBubbleEntry.isBubble());
+
+ // Demote it
+ mNotificationInfo.findViewById(R.id.alert).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry);
+ }
+
+ @Test
+ public void testSilence_demotesBubble() throws Exception {
+ mBubbleEntry.getSbn().getNotification().flags |= FLAG_BUBBLE;
+
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mNotificationChannelSet,
+ mBubbleEntry,
+ null,
+ null,
+ null,
+ true,
+ false,
+ IMPORTANCE_DEFAULT,
+ true);
+
+ assertTrue(mBubbleEntry.isBubble());
+
+ // Demote it
+ mNotificationInfo.findViewById(R.id.silence).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ verify(mBubbleController, times(1)).onUserDemotedBubbleFromNotification(mBubbleEntry);
+ }
+
+ @Test
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationInfo.bindNotification(
mMockPackageManager,
@@ -746,7 +961,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -769,7 +984,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -795,7 +1010,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -821,7 +1036,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -848,7 +1063,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -878,7 +1093,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel /* notificationChannel */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mSbn,
+ mEntry,
listener /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
@@ -917,7 +1132,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel /* notificationChannel */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mSbn,
+ mEntry,
listener /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
@@ -945,7 +1160,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel /* notificationChannel */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
- mSbn,
+ mEntry,
listener /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
@@ -970,7 +1185,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet /* numChannels */,
- mSbn,
+ mEntry,
null /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
@@ -999,7 +1214,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet /* numChannels */,
- mSbn,
+ mEntry,
null /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
@@ -1033,7 +1248,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1064,7 +1279,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1094,7 +1309,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1127,7 +1342,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1161,7 +1376,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1195,7 +1410,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1232,7 +1447,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1268,7 +1483,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1295,7 +1510,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1325,7 +1540,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1358,7 +1573,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
null,
null,
null,
@@ -1386,7 +1601,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
},
@@ -1421,7 +1636,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
},
@@ -1449,7 +1664,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME,
mNotificationChannel,
mNotificationChannelSet,
- mSbn,
+ mEntry,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
},
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 6f52e4a6686b..5b624bc6e4b3 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
@@ -20,7 +20,6 @@ import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -56,7 +55,9 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
@@ -65,9 +66,13 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.TestableNotificationEntryManager;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
@@ -80,7 +85,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.phone.StatusBarTest.TestableNotificationEntryManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -97,6 +101,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
+import java.util.List;
/**
* Tests for {@link NotificationStackScrollLayout}.
@@ -117,7 +122,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationGroupManager mGroupManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
- @Mock private NotificationData mNotificationData;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@@ -140,6 +144,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
// Inject dependencies before initializing the layout
+ mDependency.injectMockDependency(VisualStabilityManager.class);
mDependency.injectTestDependency(
NotificationBlockingHelperManager.class,
mBlockingHelperManager);
@@ -150,7 +155,18 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- mEntryManager = new TestableNotificationEntryManager(mNotificationData);
+ mEntryManager = new TestableNotificationEntryManager(
+ mock(NotifLog.class),
+ mock(NotificationGroupManager.class),
+ new NotificationRankingManager(
+ () -> mock(NotificationMediaManager.class),
+ mGroupManager,
+ mHeadsUpManager,
+ mock(NotificationFilter.class),
+ mock(NotifLog.class),
+ mock(NotificationSectionsFeatureManager.class)
+ ),
+ mock(NotificationEntryManager.KeyguardEnvironment.class));
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
@@ -161,8 +177,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// The actual class under test. You may need to work with this class directly when
// testing anonymous class members of mStackScroller, like mMenuEventListener,
// which refer to members of NotificationStackScrollLayout. The spy
- // holds a copy of the CUT's instances of these classes, so they still refer to the CUT's
- // member variables, not the spy's member variables.
+ // holds a copy of the CUT's instances of these KeyguardBypassController, so they still
+ // refer to the CUT's member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
true /* allowLongPress */, mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
@@ -293,7 +309,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_noNotifications() {
setBarStateForTest(StatusBarState.SHADE);
- assertEquals(0, mNotificationData.getActiveNotifications().size());
+ assertEquals(0, mEntryManager.getActiveNotificationsCount());
mStackScroller.updateFooter();
verify(mStackScroller, atLeastOnce()).updateFooterView(false, false);
@@ -303,8 +319,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<NotificationEntry> entries = new ArrayList<>();
- entries.add(mock(NotificationEntry.class));
- when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+ entries.add(new NotificationEntryBuilder().build());
+ addEntriesToEntryManager(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
@@ -319,9 +335,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
+
ArrayList<NotificationEntry> entries = new ArrayList<>();
- entries.add(mock(NotificationEntry.class));
- when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+ entries.add(new NotificationEntryBuilder().build());
+ addEntriesToEntryManager(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
@@ -335,10 +352,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
+
ArrayList<NotificationEntry> entries = new ArrayList<>();
- entries.add(mock(NotificationEntry.class));
- when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
- assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
+ entries.add(new NotificationEntryBuilder().build());
+ addEntriesToEntryManager(entries);
mStackScroller.updateFooter();
verify(mStackScroller).updateFooterView(true, false);
@@ -460,4 +477,14 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
mStackScroller.setStatusBarState(state);
}
+
+ private void addEntriesToEntryManager(List<NotificationEntry> entries) {
+ for (NotificationEntry e : entries) {
+ mEntryManager.addActiveNotificationForTest(e);
+ }
+ }
+
+ private void addActiveNotificationsToManager(List<NotificationEntry> entries) {
+ mEntryManager.setActiveNotificationList(entries);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 5af1e146c338..105dbad66488 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -158,26 +158,6 @@ public class DozeServiceHostTest extends SysuiTestCase {
verify(mStatusBar).updateScrimController();
}
-
- @Test
- public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() {
- // Keep track of callback to be able to stop the pulse
- final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
- doAnswer(invocation -> {
- pulseCallback[0] = invocation.getArgument(0);
- return null;
- }).when(mDozeScrimController).pulse(any(), anyInt());
-
- // Starting a pulse while docking should suppress wakeup gesture
- mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
- DozeEvent.PULSE_REASON_DOCKING);
- verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true));
-
- // Ending a pulse should restore wakeup gesture
- pulseCallback[0].onPulseFinished();
- verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false));
- }
-
@Test
public void testPulseWhileDozing_notifyAuthInterrupt() {
HashSet<Integer> reasonsWantingAuth = new HashSet<>(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index 64c1b510cbf9..a02445487dc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -40,7 +40,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
@@ -51,8 +50,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -61,7 +58,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS;
@Mock private NotificationEntryManager mEntryManager;
- @Mock private NotificationData mNotificationData;
@Mock private CommandQueue mCommandQueue;
@Mock private WindowManager mWindowManager;
@Mock private Display mDisplay;
@@ -71,7 +67,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
private View mLightsOutView;
private LightsOutNotifController mLightsOutNotifController;
- private ArrayList<NotificationEntry> mActiveNotifications = new ArrayList<>();
private int mDisplayId;
private NotificationEntryListener mEntryListener;
private CommandQueue.Callbacks mCallbacks;
@@ -81,8 +76,6 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mDisplayId = mContext.getDisplayId();
mLightsOutView = new View(mContext);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
- when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications);
when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay);
when(mDisplay.getDisplayId()).thenReturn(mDisplayId);
@@ -136,7 +129,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testLightsOut_withNotifs_onSystemBarAppearanceChanged() {
// GIVEN active visible notifications
- mActiveNotifications.add(mock(NotificationEntry.class));
+ when(mEntryManager.hasActiveNotifications()).thenReturn(true);
// WHEN lights out
mCallbacks.onSystemBarAppearanceChanged(
@@ -153,7 +146,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testLightsOut_withoutNotifs_onSystemBarAppearanceChanged() {
// GIVEN no active visible notifications
- mActiveNotifications.clear();
+ when(mEntryManager.hasActiveNotifications()).thenReturn(false);
// WHEN lights out
mCallbacks.onSystemBarAppearanceChanged(
@@ -170,7 +163,7 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testLightsOn_afterLightsOut_onSystemBarAppearanceChanged() {
// GIVEN active visible notifications
- mActiveNotifications.add(mock(NotificationEntry.class));
+ when(mEntryManager.hasActiveNotifications()).thenReturn(true);
// WHEN lights on
mCallbacks.onSystemBarAppearanceChanged(
@@ -187,13 +180,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testEntryAdded() {
// GIVEN no visible notifications and lights out
- mActiveNotifications.clear();
+ when(mEntryManager.hasActiveNotifications()).thenReturn(false);
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
mLightsOutNotifController.updateLightsOutView();
assertIsShowingDot(false);
// WHEN an active notification is added
- mActiveNotifications.add(mock(NotificationEntry.class));
+ when(mEntryManager.hasActiveNotifications()).thenReturn(true);
assertTrue(mLightsOutNotifController.shouldShowDot());
mEntryListener.onNotificationAdded(mock(NotificationEntry.class));
@@ -204,13 +197,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testEntryRemoved() {
// GIVEN a visible notification and lights out
- mActiveNotifications.add(mock(NotificationEntry.class));
+ when(mEntryManager.hasActiveNotifications()).thenReturn(true);
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
mLightsOutNotifController.updateLightsOutView();
assertIsShowingDot(true);
// WHEN all active notifications are removed
- mActiveNotifications.clear();
+ when(mEntryManager.hasActiveNotifications()).thenReturn(false);
assertFalse(mLightsOutNotifController.shouldShowDot());
mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false);
@@ -221,13 +214,13 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
@Test
public void testEntryUpdated() {
// GIVEN no visible notifications and lights out
- mActiveNotifications.clear();
+ when(mEntryManager.hasActiveNotifications()).thenReturn(false);
mLightsOutNotifController.mAppearance = LIGHTS_OUT;
mLightsOutNotifController.updateLightsOutView();
assertIsShowingDot(false);
// WHEN an active notification is added
- mActiveNotifications.add(mock(NotificationEntry.class));
+ when(mEntryManager.hasActiveNotifications()).thenReturn(true);
assertTrue(mLightsOutNotifController.shouldShowDot());
mEntryListener.onPostEntryUpdated(mock(NotificationEntry.class));
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 280cc90c0ca4..c165e561b393 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
@@ -54,11 +54,9 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -239,11 +237,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mock(ShadeController.class),
mock(NotificationLockscreenUserManager.class),
new NotificationEntryManager(
- new NotificationData(
- mock(NotificationSectionsFeatureManager.class),
- mock(NotifLog.class),
- mock(PeopleNotificationIdentifier.class)),
- mock(NotifLog.class)),
+ mock(NotifLog.class),
+ mock(NotificationGroupManager.class),
+ mock(NotificationRankingManager.class),
+ mock(NotificationEntryManager.KeyguardEnvironment.class)),
mock(KeyguardStateController.class),
statusBarStateController,
mock(DozeLog.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 85c247e11f94..4d6ff1f95caf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -50,6 +50,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -101,6 +102,8 @@ public class ScrimControllerTest extends SysuiTestCase {
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private SysuiColorExtractor mSysuiColorExtractor;
+ @Mock
+ private DockManager mDockManager;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -210,10 +213,13 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mSysuiColorExtractor.getNeutralColors()).thenReturn(new GradientColors());
+ when(mDockManager.isDocked()).thenReturn(false);
+
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController,
mResources, mDelayedWakeLockBuilder,
- new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor);
+ new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
+ mDockManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -372,6 +378,45 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
+ public void transitionToAod_afterDocked_ignoresAlwaysOnAndUpdatesFrontAlpha() {
+ // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setAodFrontScrimAlpha(0.5f);
+ finishAnimationsImmediately();
+
+ assertScrimAlpha(TRANSPARENT /* front */,
+ SEMI_TRANSPARENT /* back */,
+ TRANSPARENT /* bubble */);
+
+ // ... and doesn't take effect when disabled always_on
+ mAlwaysOnEnabled = false;
+ mScrimController.transitionTo(ScrimState.AOD);
+ finishAnimationsImmediately();
+ assertScrimAlpha(OPAQUE /* front */,
+ OPAQUE /* back */,
+ TRANSPARENT /* bubble */);
+
+ // ... but will take effect after docked
+ when(mDockManager.isDocked()).thenReturn(true);
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setAodFrontScrimAlpha(0.5f);
+ mScrimController.transitionTo(ScrimState.AOD);
+
+ assertScrimAlpha(SEMI_TRANSPARENT /* front */,
+ OPAQUE /* back */,
+ TRANSPARENT /* bubble */);
+
+ // ... and that if we set it while we're in AOD, it does take immediate effect after docked.
+ mScrimController.setAodFrontScrimAlpha(1f);
+ assertScrimAlpha(OPAQUE /* front */,
+ OPAQUE /* back */,
+ TRANSPARENT /* bubble */);
+
+ // Reset value since enums are static.
+ mScrimController.setAodFrontScrimAlpha(0f);
+ }
+
+ @Test
public void transitionToPulsing_withFrontAlphaUpdates() {
// Pre-condition
// Need to go to AoD first because PULSING doesn't change
@@ -715,38 +760,6 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
- public void transitionToPulsing_withTimeoutWallpaperCallback_willHideWallpaper() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
-
- mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {
- @Override
- public boolean shouldTimeoutWallpaper() {
- return true;
- }
- });
-
- verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
- }
-
- @Test
- public void transitionToPulsing_withDefaultCallback_wontHideWallpaper() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
-
- mScrimController.transitionTo(ScrimState.PULSING, new ScrimController.Callback() {});
-
- verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
- }
-
- @Test
- public void transitionToPulsing_withoutCallback_wontHideWallpaper() {
- mScrimController.setWallpaperSupportsAmbientMode(true);
-
- mScrimController.transitionTo(ScrimState.PULSING);
-
- verify(mAlarmManager, never()).setExact(anyInt(), anyLong(), any(), any(), any());
- }
-
- @Test
public void testConservesExpansionOpacityAfterTransition() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
mScrimController.setPanelExpansion(0.5f);
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 d8a68b0c230c..24a5d932fd85 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
@@ -68,7 +68,6 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,7 +116,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
@Mock
private Intent mContentIntentInner;
@Mock
- private NotificationData mNotificationData;
private NotificationActivityStarter mNotificationActivityStarter;
@@ -134,7 +132,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
when(mContentIntent.isActivity()).thenReturn(true);
when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1));
@@ -157,7 +154,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mActiveNotifications = new ArrayList<>();
mActiveNotifications.add(mNotificationRow.getEntry());
mActiveNotifications.add(mBubbleNotificationRow.getEntry());
- when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications);
+ when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
mNotificationActivityStarter = new StatusBarNotificationActivityStarter(getContext(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index de87d3197ef6..1c02b60902b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -52,7 +52,6 @@ import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -100,11 +99,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
mDependency.injectMockDependency(NotificationGutsManager.class);
mDependency.injectMockDependency(StatusBarWindowController.class);
mDependency.injectMockDependency(InitController.class);
- NotificationData notificationData = mock(NotificationData.class);
- when(notificationData.getNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
NotificationEntryManager entryManager =
mDependency.injectMockDependency(NotificationEntryManager.class);
- when(entryManager.getNotificationData()).thenReturn(notificationData);
+ when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
StatusBarWindowView statusBarWindowView = mock(StatusBarWindowView.class);
when(statusBarWindowView.getResources()).thenReturn(mContext.getResources());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f3273784c6ca..95929c3adcb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -101,7 +101,6 @@ import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -120,12 +119,9 @@ import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -177,7 +173,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private ArrayList<NotificationEntry> mNotificationList;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
- @Mock private NotificationData mNotificationData;
@Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private NotificationListener mNotificationListener;
@@ -240,6 +235,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private ViewMediatorCallback mViewMediatorCallback;
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private ScreenPinningRequest mScreenPinningRequest;
+ @Mock private NotificationEntryManager mEntryManager;
@Before
public void setup() throws Exception {
@@ -260,10 +256,8 @@ public class StatusBarTest extends SysuiTestCase {
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
mMetricsLogger = new FakeMetricsLogger();
- TestableNotificationEntryManager entryManager = new TestableNotificationEntryManager(
- mNotificationData);
NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
- Dependency.get(UiOffloadThread.class), entryManager, mStatusBarStateController,
+ Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController,
mExpansionStateLogger);
notificationLogger.setVisibilityReporter(mock(Runnable.class));
@@ -332,7 +326,7 @@ public class StatusBarTest extends SysuiTestCase {
),
mNotificationGutsManager,
notificationLogger,
- entryManager,
+ mEntryManager,
mNotificationInterruptionStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
@@ -407,9 +401,6 @@ public class StatusBarTest extends SysuiTestCase {
mStatusBar.mStatusBarWindowViewController = mStatusBarWindowViewController;
mStatusBar.startKeyguard();
Dependency.get(InitController.class).executePostInitTasks();
- entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller,
- mHeadsUpManager);
- entryManager.addNotificationEntryListener(mEntryListener);
notificationLogger.setUpWithContainer(mStackScroller);
}
@@ -645,8 +636,7 @@ public class StatusBarTest extends SysuiTestCase {
public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
- when(mNotificationList.size()).thenReturn(5);
+ when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true);
mStatusBar.setBarStateForTest(StatusBarState.SHADE);
@@ -664,8 +654,8 @@ public class StatusBarTest extends SysuiTestCase {
@Test
public void testPanelOpenAndClear() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
- when(mNotificationList.size()).thenReturn(5);
+ when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
+
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
mStatusBar.setBarStateForTest(StatusBarState.SHADE);
@@ -683,8 +673,7 @@ public class StatusBarTest extends SysuiTestCase {
@Test
public void testPanelOpenAndNoClear() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
- when(mNotificationList.size()).thenReturn(5);
+ when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
@@ -842,19 +831,6 @@ public class StatusBarTest extends SysuiTestCase {
any(UserHandle.class));
}
- public static class TestableNotificationEntryManager extends NotificationEntryManager {
-
- public TestableNotificationEntryManager(NotificationData notificationData) {
- super(notificationData, mock(NotifLog.class));
- }
-
- public void setUpForTest(NotificationPresenter presenter,
- NotificationListContainer listContainer,
- HeadsUpManagerPhone headsUpManager) {
- super.setUpWithPresenter(presenter, listContainer, headsUpManager);
- }
- }
-
public static class TestableNotificationInterruptionStateProvider extends
NotificationInterruptionStateProvider {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index bf81325eb6f8..4d4e9ae47d18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -29,6 +29,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
@@ -74,6 +75,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
@Mock private DozeLog mDozeLog;
@Mock private DozeParameters mDozeParameters;
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+ @Mock private DockManager mDockManager;
@Before
public void setUp() {
@@ -85,6 +87,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
mDependency.injectTestDependency(ShadeController.class, mShadeController);
when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
+ when(mDockManager.isDocked()).thenReturn(false);
mController = new StatusBarWindowViewController.Builder(
new InjectionInflationController(
@@ -103,7 +106,8 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
mDozeLog,
mDozeParameters,
new CommandQueue(mContext),
- mSuperStatusBarViewFactory)
+ mSuperStatusBarViewFactory,
+ mDockManager)
.setShadeController(mShadeController)
.build();
mController.setService(mStatusBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index fe719262937d..2854665aedb1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -69,8 +69,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
@Test
public void testRegisteredWithDispatcher() {
- verify(mBroadcastDispatcher).registerReceiver(
- any(BroadcastReceiver.class),
+ verify(mBroadcastDispatcher).registerReceiver(any(BroadcastReceiver.class),
any(IntentFilter.class),
any(Handler.class)); // VolumeDialogControllerImpl does not call with user
}
@@ -97,7 +96,8 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
when(mStatusBar.isDeviceInteractive()).thenReturn(false);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
+ when(mStatusBar.getWakefulnessState()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@@ -105,8 +105,10 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
@Test
public void testVolumeChangeW_nullStatusBar() {
VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
- TestableVolumeDialogControllerImpl nullStatusBarTestableDialog = new
- TestableVolumeDialogControllerImpl(mContext, callback, null, mBroadcastDispatcher);
+ TestableVolumeDialogControllerImpl
+ nullStatusBarTestableDialog =
+ new TestableVolumeDialogControllerImpl(
+ mContext, callback, null, mBroadcastDispatcher);
nullStatusBarTestableDialog.setEnableDialogs(true, true);
nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
@@ -127,7 +129,9 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s,
BroadcastDispatcher broadcastDispatcher) {
- super(context, broadcastDispatcher, s == null ? Optional.empty() : Optional.of(s));
+ super(
+ context, broadcastDispatcher,
+ s == null ? Optional.empty() : Optional.of(() -> s));
mCallbacks = callback;
}
}
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 56020cd573b1..748eb40cb8b8 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -24,3 +24,27 @@ android_app {
certificate: "platform",
privileged: false,
}
+
+android_test {
+ name: "WallpaperBackupAgentTests",
+ manifest: "test/AndroidManifest.xml",
+ test_config: "test/AndroidTest.xml",
+ srcs: [
+ // Include the app source code because the app runs as the system user on-device.
+ "src/**/*.java",
+ "test/src/**/*.java"
+ ],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "truth-prebuilt",
+ ],
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"]
+}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index da9018996fe7..1c2c640daa7b 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -39,6 +39,8 @@ import android.os.UserHandle;
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -89,7 +91,7 @@ public class WallpaperBackupAgent extends BackupAgent {
Slog.v(TAG, "onCreate()");
}
- File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+ File wallpaperDir = getWallpaperDir();
mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
mWallpaperFile = new File(wallpaperDir, WALLPAPER);
mLockWallpaperFile = new File(wallpaperDir, WALLPAPER_LOCK);
@@ -102,6 +104,11 @@ public class WallpaperBackupAgent extends BackupAgent {
}
}
+ @VisibleForTesting
+ protected File getWallpaperDir() {
+ return Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+ }
+
@Override
public void onFullBackup(FullBackupDataOutput data) throws IOException {
// To avoid data duplication and disk churn, use links as the stage.
@@ -119,7 +126,7 @@ public class WallpaperBackupAgent extends BackupAgent {
FileOutputStream touch = new FileOutputStream(empty);
touch.close();
}
- fullBackupFile(empty, data);
+ backupFile(empty, data);
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
final int lastSysGeneration = prefs.getInt(SYSTEM_GENERATION, -1);
@@ -155,7 +162,7 @@ public class WallpaperBackupAgent extends BackupAgent {
FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
}
if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
- fullBackupFile(infoStage, data);
+ backupFile(infoStage, data);
}
if (sysEligible && mWallpaperFile.exists()) {
if (sysChanged || !imageStage.exists()) {
@@ -163,7 +170,7 @@ public class WallpaperBackupAgent extends BackupAgent {
FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
}
if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
- fullBackupFile(imageStage, data);
+ backupFile(imageStage, data);
prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
}
@@ -174,7 +181,7 @@ public class WallpaperBackupAgent extends BackupAgent {
FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
}
if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
- fullBackupFile(lockImageStage, data);
+ backupFile(lockImageStage, data);
prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
}
} catch (Exception e) {
@@ -189,6 +196,12 @@ public class WallpaperBackupAgent extends BackupAgent {
}
}
+ @VisibleForTesting
+ // fullBackupFile is final, so we intercept backups here in tests.
+ protected void backupFile(File file, FullBackupDataOutput data) {
+ fullBackupFile(file, data);
+ }
+
@Override
public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
if (DEBUG) {
diff --git a/packages/WallpaperBackup/test/AndroidManifest.xml b/packages/WallpaperBackup/test/AndroidManifest.xml
new file mode 100644
index 000000000000..44ab1b6d65ba
--- /dev/null
+++ b/packages/WallpaperBackup/test/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wallpaperbackup.tests">
+
+ <application android:label="WallpaperBackup Tests">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wallpaperbackup.tests"
+ android:label="WallpaperBackup Tests"/>
+</manifest>
+
diff --git a/packages/WallpaperBackup/test/AndroidTest.xml b/packages/WallpaperBackup/test/AndroidTest.xml
new file mode 100644
index 000000000000..f2e77821e492
--- /dev/null
+++ b/packages/WallpaperBackup/test/AndroidTest.xml
@@ -0,0 +1,27 @@
+<!-- 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.
+-->
+<configuration description="Runs sample instrumentation test.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="WallpaperBackupAgentTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="WallpaperBackupAgentTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.wallpaperbackup.tests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
new file mode 100644
index 000000000000..46a7dfeed233
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.wallpaperbackup.tests;
+
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.WallpaperManager;
+import android.app.backup.FullBackupDataOutput;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.wallpaperbackup.WallpaperBackupAgent;
+import com.android.wallpaperbackup.utils.ContextWithServiceOverrides;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class WallpaperBackupAgentTest {
+ private static final String SYSTEM_GENERATION = "system_gen";
+ private static final String LOCK_GENERATION = "lock_gen";
+
+ @Mock private FullBackupDataOutput mOutput;
+ @Mock private WallpaperManager mWallpaperManager;
+ @Mock private SharedPreferences mSharedPreferences;
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ private ContextWithServiceOverrides mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
+ mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
+ mContext.setSharedPreferencesOverride(mSharedPreferences);
+ }
+
+ @Test
+ public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException {
+ WallpaperBackupAgent wallpaperBackupAgent = new WallpaperBackupAgent();
+ initialiseAgent(wallpaperBackupAgent);
+
+ when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
+ .thenReturn(1);
+ when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
+ .thenReturn(1);
+ when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
+ when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+
+ wallpaperBackupAgent.onFullBackup(mOutput);
+
+ verify(mOutput); // Backup of empty file only
+ }
+
+ @Test
+ public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()
+ throws IOException {
+ // Create a system wallpaper file
+ mTemporaryFolder.newFile("wallpaper_orig");
+ // Create stageing file to simulate he wallpaper being ready to back up
+ new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
+
+ WallpaperBackupAgent wallpaperBackupAgent =
+ new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
+ initialiseAgent(wallpaperBackupAgent);
+
+ SharedPreferences.Editor preferenceEditor = mock(SharedPreferences.Editor.class);
+
+ when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
+ .thenReturn(2);
+ when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
+ .thenReturn(1);
+ when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
+ when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
+ when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
+ when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+ when(mSharedPreferences.edit()).thenReturn(preferenceEditor);
+ when(preferenceEditor.putInt(eq(SYSTEM_GENERATION), eq(2))).thenReturn(preferenceEditor);
+
+ wallpaperBackupAgent.onFullBackup(mOutput);
+
+ verify(preferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(2));
+ }
+
+ private void initialiseAgent(WallpaperBackupAgent agent) {
+ agent.attach(mContext);
+ agent.onCreate();
+ }
+
+ private static class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
+ File mWallpaperBaseDirectory;
+ List<File> mBackedUpFiles = new ArrayList();
+
+ IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
+ mWallpaperBaseDirectory = wallpaperBaseDirectory;
+ }
+
+ @Override
+ protected File getWallpaperDir() {
+ return mWallpaperBaseDirectory;
+ }
+
+ @Override
+ protected void backupFile(File file, FullBackupDataOutput data) {
+ mBackedUpFiles.add(file);
+ }
+ }
+}
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java
new file mode 100644
index 000000000000..df5d74acfcad
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java
@@ -0,0 +1,64 @@
+/*
+ * 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.wallpaperbackup.utils;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ContextWithServiceOverrides extends ContextWrapper {
+ private static final String TAG = "ContextWithOverrides";
+
+ private Map<String, Object> mInjectedSystemServices = new HashMap<>();
+ private SharedPreferences mSharedPreferencesOverride;
+
+ public ContextWithServiceOverrides(Context base) {
+ super(base);
+ }
+
+ public <S> void injectSystemService(Class<S> cls, S service) {
+ final String name = getSystemServiceName(cls);
+ mInjectedSystemServices.put(name, service);
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (mInjectedSystemServices.containsKey(name)) {
+ return mInjectedSystemServices.get(name);
+ }
+ return super.getSystemService(name);
+ }
+
+ public void setSharedPreferencesOverride(SharedPreferences override) {
+ mSharedPreferencesOverride = override;
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ return mSharedPreferencesOverride == null
+ ? super.getSharedPreferences(name, mode)
+ : mSharedPreferencesOverride;
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6f435294268f..7fdd83bebbcd 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -98,6 +98,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.xmlpull.v1.XmlPullParserException;
@@ -179,6 +180,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final AccessibilityDisplayListener mA11yDisplayListener;
+ private final ActivityTaskManagerInternal mActivityTaskManagerService;
+
private final MainHandler mMainHandler;
private final SystemActionPerformer mSystemActionPerformer;
@@ -260,6 +263,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mWindowManagerService, this, mSecurityPolicy, this);
mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
+ mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
@@ -1435,7 +1439,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
service = new AccessibilityServiceConnection(userState, mContext, componentName,
installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
this, mWindowManagerService, mSystemActionPerformer,
- mA11yWindowManager);
+ mA11yWindowManager, mActivityTaskManagerService);
} else if (userState.mBoundServices.contains(service)) {
continue;
}
@@ -2411,7 +2415,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState, mContext,
COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
AccessibilityManagerService.this, mWindowManagerService,
- mSystemActionPerformer, mA11yWindowManager) {
+ mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService) {
@Override
public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
return true;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index a0a755a30cb3..6cadb6d0f31f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -35,6 +35,7 @@ import android.provider.Settings;
import android.util.Slog;
import android.view.Display;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import java.lang.ref.WeakReference;
@@ -59,6 +60,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
*/
final WeakReference<AccessibilityUserState> mUserStateWeakReference;
final Intent mIntent;
+ final ActivityTaskManagerInternal mActivityTaskManagerService;
private final Handler mMainHandler;
@@ -67,7 +69,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
WindowManagerInternal windowManagerInternal,
- SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm) {
+ SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm,
+ ActivityTaskManagerInternal activityTaskManagerService) {
super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer, awm);
mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState);
@@ -75,6 +78,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
mMainHandler = mainHandler;
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.accessibility_binding_label);
+ mActivityTaskManagerService = activityTaskManagerService;
final long identity = Binder.clearCallingIdentity();
try {
mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity(
@@ -101,6 +105,9 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
} finally {
Binder.restoreCallingIdentity(identity);
}
+ mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(),
+ mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
+ userState.mUserId);
}
public void unbindLocked() {
@@ -109,6 +116,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
if (userState == null) return;
userState.removeServiceLocked(this);
mSystemSupport.getMagnificationController().resetAllIfNeeded(mId);
+ mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
+ userState.mUserId);
resetLocked();
}
@@ -207,6 +216,11 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
public void onServiceDisconnected(ComponentName componentName) {
binderDied();
+ AccessibilityUserState userState = mUserStateWeakReference.get();
+ if (userState != null) {
+ mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
+ userState.mUserId);
+ }
}
@Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 770de09382fe..c6bc1068da39 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -91,6 +91,7 @@ java_library_static {
"android.hardware.light-V2.0-java",
"android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
+ "app-compat-annotations",
],
required: [
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3916f0d78931..dcc690fa09b4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -141,6 +141,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
+import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
@@ -196,9 +197,6 @@ class StorageManagerService extends IStorageManager.Stub
private static final String ZRAM_ENABLED_PROPERTY =
"persist.sys.zram_enabled";
- private static final boolean IS_FUSE_ENABLED =
- SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);
-
private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
/**
@@ -350,6 +348,10 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mLock")
private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
+ /** Map from volume ID to latches */
+ @GuardedBy("mLock")
+ private ArrayMap<String, CountDownLatch> mFuseVolumeReadyLatches = new ArrayMap<>();
+
@GuardedBy("mLock")
private IPackageMoveObserver mMoveCallback;
@GuardedBy("mLock")
@@ -419,7 +421,7 @@ class StorageManagerService extends IStorageManager.Stub
private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
- return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
+ return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL + ";" + 0);
} else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
return storage.getPrimaryPhysicalVolume();
} else {
@@ -462,6 +464,17 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private CountDownLatch findOrCreateFuseVolumeReadyLatch(String volId) {
+ synchronized (mLock) {
+ CountDownLatch latch = mFuseVolumeReadyLatches.get(volId);
+ if (latch == null) {
+ latch = new CountDownLatch(1);
+ mFuseVolumeReadyLatches.put(volId, latch);
+ }
+ return latch;
+ }
+ }
+
/** List of crypto types.
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
* corresponding commands in CommandListener.cpp */
@@ -514,6 +527,8 @@ class StorageManagerService extends IStorageManager.Stub
// Not guarded by a lock.
private final StorageSessionController mStorageSessionController;
+ private final boolean mIsFuseEnabled;
+
class ObbState implements IBinder.DeathRecipient {
public ObbState(String rawPath, String canonicalPath, int callingUid,
IObbActionListener token, int nonce, String volId) {
@@ -597,6 +612,7 @@ class StorageManagerService extends IStorageManager.Stub
private static final int H_ABORT_IDLE_MAINT = 12;
private static final int H_BOOT_COMPLETED = 13;
private static final int H_COMPLETE_UNLOCK_USER = 14;
+ private static final int H_VOLUME_READY = 15;
class StorageManagerServiceHandler extends Handler {
public StorageManagerServiceHandler(Looper looper) {
@@ -657,6 +673,22 @@ class StorageManagerService extends IStorageManager.Stub
}
break;
}
+ case H_VOLUME_READY: {
+ final VolumeInfo vol = (VolumeInfo) msg.obj;
+ try {
+ mStorageSessionController.onVolumeReady(vol);
+
+ synchronized (mLock) {
+ CountDownLatch latch = mFuseVolumeReadyLatches.remove(vol.id);
+ if (latch != null) {
+ latch.countDown();
+ }
+ }
+ } catch (IllegalStateException | ExternalStorageServiceException e) {
+ Slog.i(TAG, "Failed to initialise volume " + vol, e);
+ }
+ break;
+ }
case H_VOLUME_MOUNT: {
final VolumeInfo vol = (VolumeInfo) msg.obj;
if (isMountDisallowed(vol)) {
@@ -664,19 +696,12 @@ class StorageManagerService extends IStorageManager.Stub
break;
}
- // TODO(b/135341433): Remove paranoid logging when FUSE is stable
- Slog.i(TAG, "Mounting volume " + vol);
- // TODO(b/135341433): Update to use new vold API that gets or mounts fuse fd
- // Ensure that we can pass user of a volume to the new API
- mStorageSessionController.onVolumeMounted(mCurrentUserId, mount(vol), vol);
- Slog.i(TAG, "Mounted volume " + vol);
-
+ mount(vol);
break;
}
case H_VOLUME_UNMOUNT: {
final VolumeInfo vol = (VolumeInfo) msg.obj;
unmount(vol);
- mStorageSessionController.onVolumeUnmounted(mCurrentUserId, vol);
break;
}
case H_VOLUME_BROADCAST: {
@@ -757,7 +782,6 @@ class StorageManagerService extends IStorageManager.Stub
}
}
mVold.onUserRemoved(userId);
- mStorageSessionController.onUserRemoved(userId);
}
} catch (Exception e) {
Slog.wtf(TAG, e);
@@ -978,7 +1002,12 @@ class StorageManagerService extends IStorageManager.Stub
+ ", mDaemonConnected=" + mDaemonConnected);
if (mBootCompleted && mDaemonConnected) {
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
- killMediaProvider(users);
+
+ if (mIsFuseEnabled) {
+ mStorageSessionController.onReset(mVold, mHandler);
+ } else {
+ killMediaProvider(users);
+ }
final int[] systemUnlockedUsers;
synchronized (mLock) {
@@ -992,7 +1021,7 @@ class StorageManagerService extends IStorageManager.Stub
try {
// TODO(b/135341433): Remove paranoid logging when FUSE is stable
- Slog.i(TAG, "Resetting vold");
+ Slog.i(TAG, "Resetting vold...");
mVold.reset();
Slog.i(TAG, "Reset vold");
@@ -1019,7 +1048,7 @@ class StorageManagerService extends IStorageManager.Stub
// staging area is ready so it's ready for zygote-forked apps to
// bind mount against.
try {
- mStorageSessionController.onUserStarted(userId);
+ mStorageSessionController.onUnlockUser(userId);
mVold.onUserStarted(userId);
mStoraged.onUserStarted(userId);
} catch (Exception e) {
@@ -1201,10 +1230,12 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
+ public void onVolumeCreated(String volId, int type, String diskId, String partGuid,
+ int userId) {
synchronized (mLock) {
final DiskInfo disk = mDisks.get(diskId);
final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
+ vol.mountUserId = userId;
mVolumes.put(volId, vol);
onVolumeCreatedLocked(vol);
}
@@ -1258,8 +1289,13 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public void onVolumeDestroyed(String volId) {
+ VolumeInfo vol = null;
synchronized (mLock) {
- mVolumes.remove(volId);
+ vol = mVolumes.remove(volId);
+ }
+
+ if (vol != null) {
+ mStorageSessionController.onVolumeRemove(vol);
}
}
};
@@ -1395,6 +1431,13 @@ class StorageManagerService extends IStorageManager.Stub
writeSettingsLocked();
}
+ if (mIsFuseEnabled && newState == VolumeInfo.STATE_MOUNTED
+ && (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_EMULATED)) {
+ Slog.i(TAG, "Initialising volume " + vol + " ...");
+ // TODO(b/144275217): Delay broadcasts till mount is really ready
+ mHandler.obtainMessage(H_VOLUME_READY, vol).sendToTarget();
+ }
+
mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
// Do not broadcast before boot has completed to avoid launching the
@@ -1546,13 +1589,12 @@ class StorageManagerService extends IStorageManager.Stub
// Snapshot feature flag used for this boot
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
-
SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));
+ mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false);
mContext = context;
mResolver = mContext.getContentResolver();
-
mCallbacks = new Callbacks(FgThread.get().getLooper());
mLockPatternUtils = new LockPatternUtils(mContext);
@@ -1563,11 +1605,7 @@ class StorageManagerService extends IStorageManager.Stub
// Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
- mStorageSessionController = new StorageSessionController(mContext,
- userId -> {
- Slog.i(TAG, "Storage session ended for user: " + userId + ". Resetting...");
- mHandler.obtainMessage(H_RESET).sendToTarget();
- });
+ mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
// Initialize the last-fstrim tracking if necessary
File dataDir = Environment.getDataDirectory();
@@ -1873,21 +1911,36 @@ class StorageManagerService extends IStorageManager.Stub
if (isMountDisallowed(vol)) {
throw new SecurityException("Mounting " + volId + " restricted by policy");
}
+
+ CountDownLatch latch = null;
+ if (mIsFuseEnabled && StorageSessionController.isEmulatedOrPublic(vol)) {
+ latch = findOrCreateFuseVolumeReadyLatch(volId);
+ }
+
mount(vol);
+
+ if (latch != null) {
+ try {
+ waitForLatch(latch, "mount " + volId, 3 * DateUtils.MINUTE_IN_MILLIS);
+ } catch (TimeoutException e) {
+ Slog.wtf(TAG, e);
+ } finally {
+ synchronized (mLock) {
+ mFuseVolumeReadyLatches.remove(volId);
+ }
+ }
+ }
}
- private FileDescriptor mount(VolumeInfo vol) {
+ private void mount(VolumeInfo vol) {
try {
- // TODO(b/135341433): Now, emulated (and private?) volumes are shared across users
- // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which
- // requires a valid user to mount a volume. Create individual volumes per user in vold
- // and remove this property check
- int userId = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false)
- ? mCurrentUserId : vol.mountUserId;
- return mVold.mount(vol.id, vol.mountFlags, userId);
+ // TODO(b/135341433): Remove paranoid logging when FUSE is stable
+ Slog.i(TAG, "Mounting volume " + vol);
+ FileDescriptor fd = mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
+ Slog.i(TAG, "Mounted volume " + vol);
+ mStorageSessionController.onVolumeMount(fd, vol);
} catch (Exception e) {
Slog.wtf(TAG, e);
- return null;
}
}
@@ -1902,6 +1955,7 @@ class StorageManagerService extends IStorageManager.Stub
private void unmount(VolumeInfo vol) {
try {
mVold.unmount(vol.id);
+ mStorageSessionController.onVolumeUnmount(vol);
} catch (Exception e) {
Slog.wtf(TAG, e);
}
@@ -3040,6 +3094,14 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public void mkdirs(String callingPkg, String appPath) {
+ if (mIsFuseEnabled) {
+ // TODO(b/144332951): Calling into Vold is risky because the FUSE daemon can go down
+ // anytime and Vold will hang forever. We should either remove this call
+ // or at least call into the FUSE daemon to mkdir instead
+ Slog.w(TAG, "Not making dir for package " + callingPkg + " with path " + appPath);
+ return;
+ }
+
final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final UserEnvironment userEnv = new UserEnvironment(userId);
@@ -3121,8 +3183,12 @@ class StorageManagerService extends IStorageManager.Stub
switch (vol.getType()) {
case VolumeInfo.TYPE_PUBLIC:
case VolumeInfo.TYPE_STUB:
- case VolumeInfo.TYPE_EMULATED:
break;
+ case VolumeInfo.TYPE_EMULATED:
+ if (vol.getMountUserId() == userId) {
+ break;
+ }
+ // Skip if emulated volume not for userId
default:
continue;
}
@@ -3711,7 +3777,7 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (IS_FUSE_ENABLED && packageName.equals(mMediaStoreAuthorityPackageName)) {
+ if (mIsFuseEnabled && packageName.equals(mMediaStoreAuthorityPackageName)) {
// Determine if caller requires pass_through mount
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a6d216fea7e2..4bb29f014d0e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24,6 +24,7 @@ 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_TEST_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
@@ -3054,7 +3055,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* @param userId
* @param event
* @param appToken ActivityRecord's appToken.
- * @param taskRoot TaskRecord's root
+ * @param taskRoot Task's root
*/
public void updateActivityUsageStats(ComponentName activity, int userId, int event,
IBinder appToken, ComponentName taskRoot) {
@@ -16060,13 +16061,12 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
- if (disableHiddenApiChecks) {
+ boolean disableTestApiChecks = disableHiddenApiChecks
+ || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
+ if (disableHiddenApiChecks || disableTestApiChecks) {
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
"disable hidden API checks");
}
- // Allow instrumented processes access to test APIs.
- // TODO(satayev): make this configurable via testing framework.
- boolean disableTestApiChecks = true;
final boolean mountExtStorageFull = isCallerShell()
&& (flags & INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL) != 0;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59acdcf4a875..1f56176bf00d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -3028,7 +3028,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --allow-background-activity-starts: The receiver may start activities");
pw.println(" even if in the background.");
pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
- pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]");
+ pw.println(" [--user <USER_ID> | current]");
+ pw.println(" [--no-hidden-api-checks [--no-test-api-checks]]");
pw.println(" [--no-isolated-storage]");
pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>");
pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the");
@@ -3048,6 +3049,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;");
pw.println(" current user if not specified.");
pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API.");
+ pw.println(" --no-test-api-checks: disable restrictions to test APIs, if hidden");
+ pw.println(" API checks are enabled.");
pw.println(" --no-isolated-storage: don't use isolated storage sandbox and ");
pw.println(" mount full external storage");
pw.println(" --no-window-animation: turn off window animations while running.");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cd81af58dfcf..09cbc5c67ab7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -61,6 +61,7 @@ import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiTvClient;
import android.hardware.input.InputManager;
import android.hardware.usb.UsbManager;
+import android.hidl.manager.V1_0.IServiceManager;
import android.media.AudioAttributes;
import android.media.AudioFocusInfo;
import android.media.AudioFocusRequest;
@@ -148,10 +149,12 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -722,6 +725,8 @@ public class AudioService extends IAudioService.Stub
AudioSystem.setErrorCallback(mAudioSystemCallback);
+ updateAudioHalPids();
+
boolean cameraSoundForced = readCameraSoundForced();
mCameraSoundForced = new Boolean(cameraSoundForced);
sendMsg(mAudioHandler,
@@ -767,6 +772,8 @@ public class AudioService extends IAudioService.Stub
readAndSetLowRamDevice();
+ mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
+
// Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode.
mRingerAndZenModeMutedStreams = 0;
@@ -950,6 +957,8 @@ public class AudioService extends IAudioService.Stub
}
Log.e(TAG, "Audioserver started.");
+ updateAudioHalPids();
+
// indicate to audio HAL that we start the reconfiguration phase after a media
// server crash
// Note that we only execute this when the media server
@@ -958,6 +967,8 @@ public class AudioService extends IAudioService.Stub
readAndSetLowRamDevice();
+ mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
+
// Restore device connection states, BT state
mDeviceBroker.onAudioServerDied();
@@ -1462,10 +1473,13 @@ public class AudioService extends IAudioService.Stub
}
if (!TextUtils.isEmpty(packageName)) {
PackageManager pm = mContext.getPackageManager();
+ ActivityManager am =
+ (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE);
+
if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
== PackageManager.PERMISSION_GRANTED) {
try {
- assistantUid = pm.getPackageUid(packageName, 0);
+ assistantUid = pm.getPackageUidAsUser(packageName, am.getCurrentUser());
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG,
"updateAssistantUId() could not find UID for package: " + packageName);
@@ -2905,11 +2919,14 @@ public class AudioService extends IAudioService.Stub
final boolean currentMute = AudioSystem.isMicrophoneMuted();
final long identity = Binder.clearCallingIdentity();
AudioSystem.muteMicrophone(muted);
- Binder.restoreCallingIdentity(identity);
- if (muted != currentMute) {
- mContext.sendBroadcastAsUser(
+ try {
+ if (muted != currentMute) {
+ mContext.sendBroadcastAsUser(
new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
@@ -3280,6 +3297,12 @@ public class AudioService extends IAudioService.Stub
return;
}
+ if (mode == AudioSystem.MODE_CALL_SCREENING && !mIsCallScreeningModeSupported) {
+ Log.w(TAG, "setMode(MODE_CALL_SCREENING) not permitted "
+ + "when call screening is not supported");
+ return;
+ }
+
if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
return;
}
@@ -3410,6 +3433,14 @@ public class AudioService extends IAudioService.Stub
return mMode;
}
+ /** cached value read from audiopolicy manager after initialization. */
+ private boolean mIsCallScreeningModeSupported = false;
+
+ /** @see AudioManager#isCallScreeningModeSupported() */
+ public boolean isCallScreeningModeSupported() {
+ return mIsCallScreeningModeSupported;
+ }
+
//==========================================================================================
// Sound Effects
//==========================================================================================
@@ -6142,6 +6173,7 @@ public class AudioService extends IAudioService.Stub
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient);
pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported);
+ pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported);
dumpAudioPolicies(pw);
mDynPolicyLogger.dump(pw);
@@ -7301,6 +7333,41 @@ public class AudioService extends IAudioService.Stub
}
//======================
+ // Audio HAL process dump
+ //======================
+
+ private static final String AUDIO_HAL_SERVICE_PREFIX = "android.hardware.audio";
+
+ private Set<Integer> getAudioHalPids() {
+ try {
+ IServiceManager serviceManager = IServiceManager.getService();
+ ArrayList<IServiceManager.InstanceDebugInfo> dump =
+ serviceManager.debugDump();
+ HashSet<Integer> pids = new HashSet<>();
+ for (IServiceManager.InstanceDebugInfo info : dump) {
+ if (info.pid != IServiceManager.PidConstant.NO_PID
+ && info.interfaceName != null
+ && info.interfaceName.startsWith(AUDIO_HAL_SERVICE_PREFIX)) {
+ pids.add(info.pid);
+ }
+ }
+ return pids;
+ } catch (RemoteException e) {
+ return new HashSet<Integer>();
+ }
+ }
+
+ private void updateAudioHalPids() {
+ Set<Integer> pidsSet = getAudioHalPids();
+ if (pidsSet.isEmpty()) {
+ Slog.w(TAG, "Could not retrieve audio HAL service pids");
+ return;
+ }
+ int[] pidsArray = pidsSet.stream().mapToInt(Integer::intValue).toArray();
+ AudioSystem.setAudioHalPids(pidsArray);
+ }
+
+ //======================
// misc
//======================
private final HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 4a62bc507d92..bc7307b3ee6c 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -394,6 +394,15 @@ public final class ContentService extends IContentService.Stub {
* allowed.
*/
@Override
+ public void notifyChange(Uri[] uris, IContentObserver observer,
+ boolean observerWantsSelfNotifications, int flags, int userHandle,
+ int targetSdkVersion, String callingPackage) {
+ for (Uri uri : uris) {
+ notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
+ targetSdkVersion, callingPackage);
+ }
+ }
+
public void notifyChange(Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, int flags, int userHandle,
int targetSdkVersion, String callingPackage) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index ebaa5a1bd475..dea47db62b9c 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -51,6 +51,8 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -64,6 +66,9 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
@@ -428,7 +433,8 @@ public class SyncStorageEngine {
}
// Primary list of all syncable authorities. Also our global lock.
- private final SparseArray<AuthorityInfo> mAuthorities =
+ @VisibleForTesting
+ final SparseArray<AuthorityInfo> mAuthorities =
new SparseArray<AuthorityInfo>();
private final HashMap<AccountAndUser, AccountInfo> mAccounts
@@ -437,7 +443,8 @@ public class SyncStorageEngine {
private final SparseArray<ArrayList<SyncInfo>> mCurrentSyncs
= new SparseArray<ArrayList<SyncInfo>>();
- private final SparseArray<SyncStatusInfo> mSyncStatus =
+ @VisibleForTesting
+ final SparseArray<SyncStatusInfo> mSyncStatus =
new SparseArray<SyncStatusInfo>();
private final ArrayList<SyncHistoryItem> mSyncHistory =
@@ -453,7 +460,8 @@ public class SyncStorageEngine {
private int mNextAuthorityId = 0;
// We keep 4 weeks of stats.
- private final DayStats[] mDayStats = new DayStats[7*4];
+ @VisibleForTesting
+ final DayStats[] mDayStats = new DayStats[7*4];
private final Calendar mCal;
private int mYear;
private int mYearInDays;
@@ -464,6 +472,18 @@ public class SyncStorageEngine {
private int mSyncRandomOffset;
+ // STOPSHIP: b/143656271 this should be true on launch
+ private static final boolean DELETE_LEGACY_PARCEL_FILES = false;
+ private static final String LEGACY_STATUS_FILE_NAME = "status.bin";
+ private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin";
+
+ private static final String SYNC_DIR_NAME = "sync";
+ private static final String ACCOUNT_INFO_FILE_NAME = "accounts.xml";
+ private static final String STATUS_FILE_NAME = "status";
+ private static final String STATISTICS_FILE_NAME = "stats";
+
+ private File mSyncDir;
+
/**
* This file contains the core engine state: all accounts and the
* settings for them. It must never be lost, and should be changed
@@ -508,14 +528,15 @@ public class SyncStorageEngine {
com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically);
File systemDir = new File(dataDir, "system");
- File syncDir = new File(systemDir, "sync");
- syncDir.mkdirs();
+ mSyncDir = new File(systemDir, SYNC_DIR_NAME);
+ mSyncDir.mkdirs();
- maybeDeleteLegacyPendingInfoLocked(syncDir);
+ maybeDeleteLegacyPendingInfoLocked(mSyncDir);
- mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"), "sync-accounts");
- mStatusFile = new AtomicFile(new File(syncDir, "status.bin"), "sync-status");
- mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"), "sync-stats");
+ mAccountInfoFile = new AtomicFile(new File(mSyncDir, ACCOUNT_INFO_FILE_NAME),
+ "sync-accounts");
+ mStatusFile = new AtomicFile(new File(mSyncDir, STATUS_FILE_NAME), "sync-status");
+ mStatisticsFile = new AtomicFile(new File(mSyncDir, STATISTICS_FILE_NAME), "sync-stats");
readAccountInfoLocked();
readStatusLocked();
@@ -2017,15 +2038,10 @@ public class SyncStorageEngine {
public static final int STATUS_FILE_END = 0;
public static final int STATUS_FILE_ITEM = 100;
- /**
- * Read all sync status back in to the initial engine state.
- */
- private void readStatusLocked() {
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Slog.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile());
- }
+ private void readStatusParcelLocked(File parcel) {
try {
- byte[] data = mStatusFile.readFully();
+ final AtomicFile parcelFile = new AtomicFile(parcel);
+ byte[] data = parcelFile.readFully();
Parcel in = Parcel.obtain();
in.unmarshall(data, 0, data.length);
in.setDataPosition(0);
@@ -2036,9 +2052,6 @@ public class SyncStorageEngine {
SyncStatusInfo status = new SyncStatusInfo(in);
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
status.pending = false;
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Slog.v(TAG_FILE, "Adding status for id " + status.authorityId);
- }
mSyncStatus.put(status.authorityId, status);
}
} catch (Exception e) {
@@ -2050,15 +2063,247 @@ public class SyncStorageEngine {
break;
}
}
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
Slog.i(TAG, "No initial status");
}
}
+ private void upgradeStatusIfNeededLocked() {
+ final File parcelStatus = new File(mSyncDir, LEGACY_STATUS_FILE_NAME);
+ if (parcelStatus.exists() && !mStatusFile.exists()) {
+ readStatusParcelLocked(parcelStatus);
+ writeStatusLocked();
+ }
+
+ // if upgrade to proto was successful, delete parcel file
+ if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) {
+ parcelStatus.delete();
+ }
+ }
+
+ /**
+ * Read all sync status back in to the initial engine state.
+ */
+ @VisibleForTesting
+ void readStatusLocked() {
+ upgradeStatusIfNeededLocked();
+
+ if (!mStatusFile.exists()) {
+ return;
+ }
+ try {
+ try (FileInputStream in = mStatusFile.openRead()) {
+ readStatusInfoLocked(in);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read status info file.", e);
+ }
+ }
+
+ private void readStatusInfoLocked(InputStream in) throws IOException {
+ final ProtoInputStream proto = new ProtoInputStream(in);
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatusProto.STATUS:
+ final long token = proto.start(SyncStatusProto.STATUS);
+ final SyncStatusInfo status = readSyncStatusInfoLocked(proto);
+ proto.end(token);
+ if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
+ status.pending = false;
+ mSyncStatus.put(status.authorityId, status);
+ }
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return;
+ }
+ }
+ }
+
+ private SyncStatusInfo readSyncStatusInfoLocked(ProtoInputStream proto) throws IOException {
+ SyncStatusInfo status;
+ if (proto.nextField(SyncStatusProto.StatusInfo.AUTHORITY_ID)) {
+ //fast-path; this should work for most cases since the authority id is written first
+ status = new SyncStatusInfo(proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID));
+ } else {
+ // placeholder to read other data; assume the default authority id as 0
+ status = new SyncStatusInfo(0);
+ }
+
+ int successTimesCount = 0;
+ int failureTimesCount = 0;
+ ArrayList<Pair<Long, String>> lastEventInformation = new ArrayList<>();
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatusProto.StatusInfo.AUTHORITY_ID:
+ // fast-path failed for some reason, rebuild the status from placeholder object
+ Slog.w(TAG, "Failed to read the authority id via fast-path; "
+ + "some data might not have been read.");
+ status = new SyncStatusInfo(
+ proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID), status);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME:
+ status.lastSuccessTime = proto.readLong(
+ SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE:
+ status.lastSuccessSource = proto.readInt(
+ SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_TIME:
+ status.lastFailureTime = proto.readLong(
+ SyncStatusProto.StatusInfo.LAST_FAILURE_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE:
+ status.lastFailureSource = proto.readInt(
+ SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE:
+ status.lastFailureMesg = proto.readString(
+ SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE);
+ break;
+ case (int) SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME:
+ status.initialFailureTime = proto.readLong(
+ SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.PENDING:
+ status.pending = proto.readBoolean(SyncStatusProto.StatusInfo.PENDING);
+ break;
+ case (int) SyncStatusProto.StatusInfo.INITIALIZE:
+ status.initialize = proto.readBoolean(SyncStatusProto.StatusInfo.INITIALIZE);
+ break;
+ case (int) SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES:
+ status.addPeriodicSyncTime(
+ proto.readLong(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES));
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_EVENT_INFO:
+ final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
+ final Pair<Long, String> lastEventInfo = parseLastEventInfoLocked(proto);
+ if (lastEventInfo != null) {
+ lastEventInformation.add(lastEventInfo);
+ }
+ proto.end(eventToken);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME:
+ status.lastTodayResetTime = proto.readLong(
+ SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.TOTAL_STATS:
+ final long totalStatsToken = proto.start(
+ SyncStatusProto.StatusInfo.TOTAL_STATS);
+ readSyncStatusStatsLocked(proto, status.totalStats);
+ proto.end(totalStatsToken);
+ break;
+ case (int) SyncStatusProto.StatusInfo.TODAY_STATS:
+ final long todayStatsToken = proto.start(
+ SyncStatusProto.StatusInfo.TODAY_STATS);
+ readSyncStatusStatsLocked(proto, status.todayStats);
+ proto.end(todayStatsToken);
+ break;
+ case (int) SyncStatusProto.StatusInfo.YESTERDAY_STATS:
+ final long yesterdayStatsToken = proto.start(
+ SyncStatusProto.StatusInfo.YESTERDAY_STATS);
+ readSyncStatusStatsLocked(proto, status.yesterdayStats);
+ proto.end(yesterdayStatsToken);
+ break;
+ case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES:
+ final long successTime = proto.readLong(
+ SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES);
+ if (successTimesCount == status.perSourceLastSuccessTimes.length) {
+ Slog.w(TAG, "Attempted to read more per source last success times "
+ + "than expected; data might be corrupted.");
+ break;
+ }
+ status.perSourceLastSuccessTimes[successTimesCount] = successTime;
+ successTimesCount++;
+ break;
+ case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES:
+ final long failureTime = proto.readLong(
+ SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES);
+ if (failureTimesCount == status.perSourceLastFailureTimes.length) {
+ Slog.w(TAG, "Attempted to read more per source last failure times "
+ + "than expected; data might be corrupted.");
+ break;
+ }
+ status.perSourceLastFailureTimes[failureTimesCount] = failureTime;
+ failureTimesCount++;
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ status.populateLastEventsInformation(lastEventInformation);
+ return status;
+ }
+ }
+ }
+
+ private Pair<Long, String> parseLastEventInfoLocked(ProtoInputStream proto) throws IOException {
+ long time = 0;
+ String message = null;
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME:
+ time = proto.readLong(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT:
+ message = proto.readString(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT);
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return message == null ? null : new Pair<>(time, message);
+ }
+ }
+ }
+
+ private void readSyncStatusStatsLocked(ProtoInputStream proto, SyncStatusInfo.Stats stats)
+ throws IOException {
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME:
+ stats.totalElapsedTime = proto.readLong(
+ SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SYNCS:
+ stats.numSyncs = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_FAILURES:
+ stats.numFailures = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_FAILURES);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_CANCELS:
+ stats.numCancels = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER:
+ stats.numSourceOther = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL:
+ stats.numSourceLocal = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL:
+ stats.numSourcePoll = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER:
+ stats.numSourceUser = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC:
+ stats.numSourcePeriodic = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC);
+ break;
+ case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED:
+ stats.numSourceFeed = proto.readInt(
+ SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED);
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return;
+ }
+ }
+ }
+
/**
* Write all sync status to the sync status file.
*/
- private void writeStatusLocked() {
+ @VisibleForTesting
+ void writeStatusLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
Slog.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile());
}
@@ -2070,24 +2315,85 @@ public class SyncStorageEngine {
FileOutputStream fos = null;
try {
fos = mStatusFile.startWrite();
- Parcel out = Parcel.obtain();
- final int N = mSyncStatus.size();
- for (int i=0; i<N; i++) {
- SyncStatusInfo status = mSyncStatus.valueAt(i);
- out.writeInt(STATUS_FILE_ITEM);
- status.writeToParcel(out, 0);
- }
- out.writeInt(STATUS_FILE_END);
- fos.write(out.marshall());
- out.recycle();
-
+ writeStatusInfoLocked(fos);
mStatusFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
- Slog.w(TAG, "Error writing status", e1);
- if (fos != null) {
- mStatusFile.failWrite(fos);
- }
- }
+ fos = null;
+ } catch (IOException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write sync status to proto.", e);
+ } finally {
+ // when fos is null (successful write), this is a no-op.
+ mStatusFile.failWrite(fos);
+ }
+ }
+
+ private void writeStatusInfoLocked(OutputStream out) {
+ final ProtoOutputStream proto = new ProtoOutputStream(out);
+ final int size = mSyncStatus.size();
+ for (int i = 0; i < size; i++) {
+ final SyncStatusInfo info = mSyncStatus.valueAt(i);
+ final long token = proto.start(SyncStatusProto.STATUS);
+ // authority id should be written first to take advantage of the fast path in read
+ proto.write(SyncStatusProto.StatusInfo.AUTHORITY_ID, info.authorityId);
+ proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME, info.lastSuccessTime);
+ proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE, info.lastSuccessSource);
+ proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_TIME, info.lastFailureTime);
+ proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE, info.lastFailureSource);
+ proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE, info.lastFailureMesg);
+ proto.write(SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME, info.initialFailureTime);
+ proto.write(SyncStatusProto.StatusInfo.PENDING, info.pending);
+ proto.write(SyncStatusProto.StatusInfo.INITIALIZE, info.initialize);
+ final int periodicSyncTimesSize = info.getPeriodicSyncTimesSize();
+ for (int j = 0; j < periodicSyncTimesSize; j++) {
+ proto.write(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES,
+ info.getPeriodicSyncTime(j));
+ }
+ final int lastEventsSize = info.getEventCount();
+ for (int j = 0; j < lastEventsSize; j++) {
+ final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
+ proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME,
+ info.getEventTime(j));
+ proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT, info.getEvent(j));
+ proto.end(eventToken);
+ }
+ proto.write(SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME, info.lastTodayResetTime);
+
+ final long totalStatsToken = proto.start(SyncStatusProto.StatusInfo.TOTAL_STATS);
+ writeStatusStatsLocked(proto, info.totalStats);
+ proto.end(totalStatsToken);
+ final long todayStatsToken = proto.start(SyncStatusProto.StatusInfo.TODAY_STATS);
+ writeStatusStatsLocked(proto, info.todayStats);
+ proto.end(todayStatsToken);
+ final long yesterdayStatsToken = proto.start(
+ SyncStatusProto.StatusInfo.YESTERDAY_STATS);
+ writeStatusStatsLocked(proto, info.yesterdayStats);
+ proto.end(yesterdayStatsToken);
+
+ final int lastSuccessTimesSize = info.perSourceLastSuccessTimes.length;
+ for (int j = 0; j < lastSuccessTimesSize; j++) {
+ proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES,
+ info.perSourceLastSuccessTimes[j]);
+ }
+ final int lastFailureTimesSize = info.perSourceLastFailureTimes.length;
+ for (int j = 0; j < lastFailureTimesSize; j++) {
+ proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES,
+ info.perSourceLastFailureTimes[j]);
+ }
+ proto.end(token);
+ }
+ proto.flush();
+ }
+
+ private void writeStatusStatsLocked(ProtoOutputStream proto, SyncStatusInfo.Stats stats) {
+ proto.write(SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME, stats.totalElapsedTime);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS, stats.numSyncs);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_FAILURES, stats.numFailures);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS, stats.numCancels);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER, stats.numSourceOther);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL, stats.numSourceLocal);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL, stats.numSourcePoll);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER, stats.numSourceUser);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC, stats.numSourcePeriodic);
+ proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED, stats.numSourceFeed);
}
private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras,
@@ -2126,20 +2432,17 @@ public class SyncStorageEngine {
public static final int STATISTICS_FILE_ITEM_OLD = 100;
public static final int STATISTICS_FILE_ITEM = 101;
- /**
- * Read all sync statistics back in to the initial engine state.
- */
- private void readStatisticsLocked() {
+ private void readStatsParcelLocked(File parcel) {
try {
- byte[] data = mStatisticsFile.readFully();
+ final AtomicFile parcelFile = new AtomicFile(parcel);
+ byte[] data = parcelFile.readFully();
Parcel in = Parcel.obtain();
in.unmarshall(data, 0, data.length);
in.setDataPosition(0);
int token;
int index = 0;
while ((token=in.readInt()) != STATISTICS_FILE_END) {
- if (token == STATISTICS_FILE_ITEM
- || token == STATISTICS_FILE_ITEM_OLD) {
+ if (token == STATISTICS_FILE_ITEM || token == STATISTICS_FILE_ITEM_OLD) {
int day = in.readInt();
if (token == STATISTICS_FILE_ITEM_OLD) {
day = day - 2009 + 14245; // Magic!
@@ -2159,15 +2462,110 @@ public class SyncStorageEngine {
break;
}
}
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
Slog.i(TAG, "No initial statistics");
}
}
+ private void upgradeStatisticsIfNeededLocked() {
+ final File parcelStats = new File(mSyncDir, LEGACY_STATISTICS_FILE_NAME);
+ if (parcelStats.exists() && !mStatisticsFile.exists()) {
+ readStatsParcelLocked(parcelStats);
+ writeStatisticsLocked();
+ }
+
+ // if upgrade to proto was successful, delete parcel file
+ if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) {
+ parcelStats.delete();
+ }
+ }
+
+ /**
+ * Read all sync statistics back in to the initial engine state.
+ */
+ private void readStatisticsLocked() {
+ upgradeStatisticsIfNeededLocked();
+
+ if (!mStatisticsFile.exists()) {
+ return;
+ }
+ try {
+ try (FileInputStream in = mStatisticsFile.openRead()) {
+ readDayStatsLocked(in);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read day stats file.", e);
+ }
+ }
+
+ private void readDayStatsLocked(InputStream in) throws IOException {
+ final ProtoInputStream proto = new ProtoInputStream(in);
+ int statsCount = 0;
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatisticsProto.STATS:
+ final long token = proto.start(SyncStatisticsProto.STATS);
+ final DayStats stats = readIndividualDayStatsLocked(proto);
+ proto.end(token);
+ mDayStats[statsCount] = stats;
+ statsCount++;
+ if (statsCount == mDayStats.length) {
+ return;
+ }
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return;
+ }
+ }
+ }
+
+ private DayStats readIndividualDayStatsLocked(ProtoInputStream proto) throws IOException {
+ DayStats stats;
+ if (proto.nextField(SyncStatisticsProto.DayStats.DAY)) {
+ // fast-path; this should work for most cases since the day is written first
+ stats = new DayStats(proto.readInt(SyncStatisticsProto.DayStats.DAY));
+ } else {
+ // placeholder to read other data; assume the default day as 0
+ stats = new DayStats(0);
+ }
+
+ while (true) {
+ switch (proto.nextField()) {
+ case (int) SyncStatisticsProto.DayStats.DAY:
+ // fast-path failed for some reason, rebuild stats from placeholder object
+ Slog.w(TAG, "Failed to read the day via fast-path; some data "
+ + "might not have been read.");
+ final DayStats temp = new DayStats(
+ proto.readInt(SyncStatisticsProto.DayStats.DAY));
+ temp.successCount = stats.successCount;
+ temp.successTime = stats.successTime;
+ temp.failureCount = stats.failureCount;
+ temp.failureTime = stats.failureTime;
+ stats = temp;
+ break;
+ case (int) SyncStatisticsProto.DayStats.SUCCESS_COUNT:
+ stats.successCount = proto.readInt(SyncStatisticsProto.DayStats.SUCCESS_COUNT);
+ break;
+ case (int) SyncStatisticsProto.DayStats.SUCCESS_TIME:
+ stats.successTime = proto.readLong(SyncStatisticsProto.DayStats.SUCCESS_TIME);
+ break;
+ case (int) SyncStatisticsProto.DayStats.FAILURE_COUNT:
+ stats.failureCount = proto.readInt(SyncStatisticsProto.DayStats.FAILURE_COUNT);
+ break;
+ case (int) SyncStatisticsProto.DayStats.FAILURE_TIME:
+ stats.failureTime = proto.readLong(SyncStatisticsProto.DayStats.FAILURE_TIME);
+ break;
+ case ProtoInputStream.NO_MORE_FIELDS:
+ return stats;
+ }
+ }
+ }
+
/**
* Write all sync statistics to the sync status file.
*/
- private void writeStatisticsLocked() {
+ @VisibleForTesting
+ void writeStatisticsLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
Slog.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
}
@@ -2179,31 +2577,36 @@ public class SyncStorageEngine {
FileOutputStream fos = null;
try {
fos = mStatisticsFile.startWrite();
- Parcel out = Parcel.obtain();
- final int N = mDayStats.length;
- for (int i=0; i<N; i++) {
- DayStats ds = mDayStats[i];
- if (ds == null) {
- break;
- }
- out.writeInt(STATISTICS_FILE_ITEM);
- out.writeInt(ds.day);
- out.writeInt(ds.successCount);
- out.writeLong(ds.successTime);
- out.writeInt(ds.failureCount);
- out.writeLong(ds.failureTime);
- }
- out.writeInt(STATISTICS_FILE_END);
- fos.write(out.marshall());
- out.recycle();
-
+ writeDayStatsLocked(fos);
mStatisticsFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
- Slog.w(TAG, "Error writing stats", e1);
- if (fos != null) {
- mStatisticsFile.failWrite(fos);
- }
- }
+ fos = null;
+ } catch (IOException | IllegalArgumentException e) {
+ Slog.e(TAG, "Unable to write day stats to proto.", e);
+ } finally {
+ // when fos is null (successful write), this is a no-op.
+ mStatisticsFile.failWrite(fos);
+ }
+ }
+
+ private void writeDayStatsLocked(OutputStream out)
+ throws IOException, IllegalArgumentException {
+ final ProtoOutputStream proto = new ProtoOutputStream(out);
+ final int size = mDayStats.length;
+ for (int i = 0; i < size; i++) {
+ final DayStats stats = mDayStats[i];
+ if (stats == null) {
+ break;
+ }
+ final long token = proto.start(SyncStatisticsProto.STATS);
+ // day should be written first to take advantage of the fast path in read
+ proto.write(SyncStatisticsProto.DayStats.DAY, stats.day);
+ proto.write(SyncStatisticsProto.DayStats.SUCCESS_COUNT, stats.successCount);
+ proto.write(SyncStatisticsProto.DayStats.SUCCESS_TIME, stats.successTime);
+ proto.write(SyncStatisticsProto.DayStats.FAILURE_COUNT, stats.failureCount);
+ proto.write(SyncStatisticsProto.DayStats.FAILURE_TIME, stats.failureTime);
+ proto.end(token);
+ }
+ proto.flush();
}
/**
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index a7b90510e6c8..dcef99817fac 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -150,10 +150,6 @@ final class LogicalDisplay {
mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
- mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
- mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
- mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
- mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
mInfo.rotation = mOverrideDisplayInfo.rotation;
mInfo.displayCutout = mOverrideDisplayInfo.displayCutout;
mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
diff --git a/services/core/java/com/android/server/integrity/model/AtomicFormula.java b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
index a75752841cbc..70ab98c86cda 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
@@ -177,6 +177,14 @@ public abstract class AtomicFormula implements Formula {
dest.writeInt(mOperator);
}
+ public int getValue() {
+ return mValue;
+ }
+
+ public int getOperator() {
+ return mOperator;
+ }
+
private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case VERSION_CODE:
@@ -271,6 +279,10 @@ public abstract class AtomicFormula implements Formula {
dest.writeStringNoHelper(mValue);
}
+ public String getValue() {
+ return mValue;
+ }
+
private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case PACKAGE_NAME:
@@ -367,6 +379,10 @@ public abstract class AtomicFormula implements Formula {
dest.writeByte((byte) (mValue ? 1 : 0));
}
+ public boolean getValue() {
+ return mValue;
+ }
+
private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case PRE_INSTALLED:
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParseException.java b/services/core/java/com/android/server/integrity/parser/RuleParseException.java
new file mode 100644
index 000000000000..c0f36a66528a
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleParseException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when rule parsing fails.
+ */
+public class RuleParseException extends Exception {
+ public RuleParseException(@NonNull String message) {
+ super(message);
+ }
+
+ public RuleParseException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index bfffc70bb12c..08e0a5db8c20 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -25,8 +25,8 @@ import java.util.List;
public interface RuleParser {
/** Parse rules from a string. */
- List<Rule> parse(String ruleText);
+ List<Rule> parse(String ruleText) throws RuleParseException;
/** Parse rules from an input stream. */
- List<Rule> parse(InputStream inputStream);
+ List<Rule> parse(InputStream inputStream) throws RuleParseException;
}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index bf31bb2c3665..23d0b40f08f6 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -16,9 +16,11 @@
package com.android.server.integrity.parser;
-import android.util.Slog;
import android.util.Xml;
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
import org.xmlpull.v1.XmlPullParser;
@@ -38,49 +40,56 @@ public final class RuleXmlParser implements RuleParser {
public static final String TAG = "RuleXmlParser";
- private static final String RULE_LIST_TAG = "RuleList";
- private static final String RULE_TAG = "Rule";
+ // TODO: Use XML attributes
+ private static final String RULE_LIST_TAG = "RL";
+ private static final String RULE_TAG = "R";
+ private static final String OPEN_FORMULA_TAG = "OF";
+ private static final String ATOMIC_FORMULA_TAG = "AF";
+ private static final String EFFECT_TAG = "E";
+ private static final String KEY_TAG = "K";
+ private static final String OPERATOR_TAG = "O";
+ private static final String VALUE_TAG = "V";
+ private static final String CONNECTOR_TAG = "C";
@Override
- public List<Rule> parse(String ruleText) {
+ public List<Rule> parse(String ruleText) throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(new StringReader(ruleText));
return parseRules(xmlPullParser);
- } catch (XmlPullParserException | IOException e) {
- Slog.e(TAG, String.format("Unable to read rules from string: %s", ruleText), e);
+ } catch (Exception e) {
+ throw new RuleParseException(e.getMessage(), e);
}
- return null;
}
@Override
- public List<Rule> parse(InputStream inputStream) {
+ public List<Rule> parse(InputStream inputStream) throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
return parseRules(xmlPullParser);
- } catch (XmlPullParserException | IOException e) {
- Slog.e(TAG, "Unable to read rules from stream", e);
+ } catch (Exception e) {
+ throw new RuleParseException(e.getMessage(), e);
}
- return null;
}
- private List<Rule> parseRules(XmlPullParser parser) throws IOException, XmlPullParserException {
+ private static List<Rule> parseRules(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
List<Rule> rules = new ArrayList<>();
// Skipping the first event type, which is always {@link XmlPullParser.START_DOCUMENT}
parser.next();
- // Processing the first tag; which should always be a <RuleList> tag.
+ // Processing the first tag; which should always be a RuleList <RL> tag.
String nodeName = parser.getName();
- // Validating that the XML is starting with a <RuleList> tag.
+ // Validating that the XML is starting with a RuleList <RL> tag.
// Note: This is the only breaking validation to run against XML files in the platform.
// All rules inside are assumed to be validated at the server. If a rule is found to be
// corrupt in the XML, it will be skipped to the next rule.
if (!nodeName.equals(RULE_LIST_TAG)) {
throw new RuntimeException(
- String.format("Rules must start with <RuleList> tag. Found: %s at %s", nodeName,
- parser.getPositionDescription()));
+ String.format("Rules must start with RuleList <RL> tag. Found: %s at %s",
+ nodeName, parser.getPositionDescription()));
}
int eventType;
@@ -89,17 +98,150 @@ public final class RuleXmlParser implements RuleParser {
if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
continue;
}
- Rule parsedRule = parseRule(parser);
- if (parsedRule != null) {
- rules.add(parsedRule);
- }
+ rules.add(parseRule(parser));
}
return rules;
}
- private Rule parseRule(XmlPullParser parser) {
- // TODO: Implement rule parser.
- return null;
+ private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException {
+ Formula formula = null;
+ @Rule.Effect int effect = 0;
+
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ String nodeName = parser.getName();
+
+ if (eventType == XmlPullParser.END_TAG && parser.getName().equals(RULE_TAG)) {
+ break;
+ }
+
+ if (eventType == XmlPullParser.START_TAG) {
+ switch (nodeName) {
+ case OPEN_FORMULA_TAG:
+ formula = parseOpenFormula(parser);
+ break;
+ case ATOMIC_FORMULA_TAG:
+ formula = parseAtomicFormula(parser);
+ break;
+ case EFFECT_TAG:
+ effect = Integer.parseInt(extractValue(parser));
+ break;
+ default:
+ throw new RuntimeException(
+ String.format("Found unexpected tag: %s", nodeName));
+ }
+ } else {
+ throw new RuntimeException(
+ String.format("Found unexpected event type: %d", eventType));
+ }
+ }
+
+ return new Rule(formula, effect);
+ }
+
+ private static Formula parseOpenFormula(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ @OpenFormula.Connector int connector = 0;
+ List<Formula> formulas = new ArrayList<>();
+
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ String nodeName = parser.getName();
+
+ if (eventType == XmlPullParser.END_TAG && parser.getName().equals(OPEN_FORMULA_TAG)) {
+ break;
+ }
+
+ if (eventType == XmlPullParser.START_TAG) {
+ switch (nodeName) {
+ case CONNECTOR_TAG:
+ connector = Integer.parseInt(extractValue(parser));
+ break;
+ case ATOMIC_FORMULA_TAG:
+ formulas.add(parseAtomicFormula(parser));
+ break;
+ case OPEN_FORMULA_TAG:
+ formulas.add(parseOpenFormula(parser));
+ break;
+ default:
+ throw new RuntimeException(
+ String.format("Found unexpected tag: %s", nodeName));
+ }
+ } else {
+ throw new RuntimeException(
+ String.format("Found unexpected event type: %d", eventType));
+ }
+ }
+
+ return new OpenFormula(connector, formulas);
+ }
+
+ private static Formula parseAtomicFormula(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ @AtomicFormula.Key int key = 0;
+ @AtomicFormula.Operator int operator = 0;
+ String value = null;
+
+ int eventType;
+ while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ String nodeName = parser.getName();
+
+ if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ATOMIC_FORMULA_TAG)) {
+ break;
+ }
+
+ if (eventType == XmlPullParser.START_TAG) {
+ switch (nodeName) {
+ case KEY_TAG:
+ key = Integer.parseInt(extractValue(parser));
+ break;
+ case OPERATOR_TAG:
+ operator = Integer.parseInt(extractValue(parser));
+ break;
+ case VALUE_TAG:
+ value = extractValue(parser);
+ break;
+ default:
+ throw new RuntimeException(
+ String.format("Found unexpected tag: %s", nodeName));
+ }
+ } else {
+ throw new RuntimeException(
+ String.format("Found unexpected event type: %d", eventType));
+ }
+ }
+ return constructAtomicFormulaBasedOnKey(key, operator, value);
+ }
+
+ private static Formula constructAtomicFormulaBasedOnKey(@AtomicFormula.Key int key,
+ @AtomicFormula.Operator int operator, String value) {
+ switch (key) {
+ case AtomicFormula.PACKAGE_NAME:
+ case AtomicFormula.INSTALLER_NAME:
+ case AtomicFormula.APP_CERTIFICATE:
+ case AtomicFormula.INSTALLER_CERTIFICATE:
+ return new AtomicFormula.StringAtomicFormula(key, value);
+ case AtomicFormula.PRE_INSTALLED:
+ return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value));
+ case AtomicFormula.VERSION_CODE:
+ return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value));
+ default:
+ throw new RuntimeException(String.format("Found unexpected key: %d", key));
+ }
+ }
+
+ private static String extractValue(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String value;
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.TEXT) {
+ value = parser.getText();
+ eventType = parser.next();
+ if (eventType == XmlPullParser.END_TAG) {
+ return value;
+ }
+ }
+ throw new RuntimeException(String.format("Found unexpected event type: %d", eventType));
}
}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index ecb00a4b7025..ee95d2bb4d69 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -19,17 +19,18 @@ package com.android.server.integrity.serializer;
import com.android.server.integrity.model.Rule;
import java.io.OutputStream;
+import java.util.List;
/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
public class RuleBinarySerializer implements RuleSerializer {
@Override
- public void serialize(Rule rule, OutputStream outputStream) {
+ public void serialize(List<Rule> rules, OutputStream outputStream) {
// TODO: Implement stream serializer.
}
@Override
- public String serialize(Rule rule) {
+ public String serialize(List<Rule> rules) {
// TODO: Implement text serializer.
return null;
}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
new file mode 100644
index 000000000000..60cfc4876414
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.serializer;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when rule serialization fails.
+ */
+public class RuleSerializeException extends Exception {
+ public RuleSerializeException(@NonNull String message) {
+ super(message);
+ }
+
+ public RuleSerializeException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
index 07a912f8aeab..5c99c5a4c2da 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -19,13 +19,14 @@ package com.android.server.integrity.serializer;
import com.android.server.integrity.model.Rule;
import java.io.OutputStream;
+import java.util.List;
/** A helper class to serialize rules from the {@link Rule} model. */
public interface RuleSerializer {
- /** Serialize a rule to an output stream */
- void serialize(Rule rule, OutputStream outputStream);
+ /** Serialize rules to an output stream */
+ void serialize(List<Rule> rules, OutputStream outputStream) throws RuleSerializeException;
- /** Serialize a rule to a string. */
- String serialize(Rule rule);
+ /** Serialize rules to a string. */
+ String serialize(List<Rule> rule) throws RuleSerializeException;
}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index 62973e2b026f..b0805fc488cb 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -16,21 +16,142 @@
package com.android.server.integrity.serializer;
+import android.util.Xml;
+
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
import java.io.OutputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
-/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
+/**
+ * A helper class to serialize rules from the {@link Rule} model to Xml representation.
+ */
public class RuleXmlSerializer implements RuleSerializer {
+ public static final String TAG = "RuleXmlSerializer";
+ private static final String NAMESPACE = "";
+
+ private static final String RULE_LIST_TAG = "RL";
+ private static final String RULE_TAG = "R";
+ private static final String OPEN_FORMULA_TAG = "OF";
+ private static final String ATOMIC_FORMULA_TAG = "AF";
+ private static final String EFFECT_TAG = "E";
+ private static final String KEY_TAG = "K";
+ private static final String OPERATOR_TAG = "O";
+ private static final String VALUE_TAG = "V";
+ private static final String CONNECTOR_TAG = "C";
+
@Override
- public void serialize(Rule rule, OutputStream outputStream) {
- // TODO: Implement stream serializer.
+ public void serialize(List<Rule> rules, OutputStream outputStream)
+ throws RuleSerializeException {
+ try {
+ XmlSerializer xmlSerializer = Xml.newSerializer();
+ xmlSerializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ serializeRules(rules, xmlSerializer);
+ } catch (Exception e) {
+ throw new RuleSerializeException(e.getMessage(), e);
+ }
}
@Override
- public String serialize(Rule rule) {
- // TODO: Implement text serializer.
- return null;
+ public String serialize(List<Rule> rules) throws RuleSerializeException {
+ try {
+ XmlSerializer xmlSerializer = Xml.newSerializer();
+ StringWriter writer = new StringWriter();
+ xmlSerializer.setOutput(writer);
+ serializeRules(rules, xmlSerializer);
+ return writer.toString();
+ } catch (Exception e) {
+ throw new RuleSerializeException(e.getMessage(), e);
+ }
+ }
+
+ private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException {
+ xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);
+ for (Rule rule : rules) {
+ serialize(rule, xmlSerializer);
+ }
+ xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
+ xmlSerializer.endDocument();
+ }
+
+ private void serialize(Rule rule, XmlSerializer xmlSerializer) throws IOException {
+ if (rule == null) {
+ return;
+ }
+ xmlSerializer.startTag(NAMESPACE, RULE_TAG);
+ serializeFormula(rule.getFormula(), xmlSerializer);
+ serializeValue(EFFECT_TAG, String.valueOf(rule.getEffect()), xmlSerializer);
+ xmlSerializer.endTag(NAMESPACE, RULE_TAG);
+ }
+
+ private void serializeFormula(Formula formula, XmlSerializer xmlSerializer) throws IOException {
+ if (formula instanceof AtomicFormula) {
+ serializeAtomicFormula((AtomicFormula) formula, xmlSerializer);
+ } else if (formula instanceof OpenFormula) {
+ serializeOpenFormula((OpenFormula) formula, xmlSerializer);
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Invalid formula type: %s", formula.getClass()));
+ }
+ }
+
+ private void serializeOpenFormula(OpenFormula openFormula, XmlSerializer xmlSerializer)
+ throws IOException {
+ if (openFormula == null) {
+ return;
+ }
+ xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG);
+ serializeValue(CONNECTOR_TAG, String.valueOf(openFormula.getConnector()), xmlSerializer);
+ for (Formula formula : openFormula.getFormulas()) {
+ serializeFormula(formula, xmlSerializer);
+ }
+ xmlSerializer.endTag(NAMESPACE, OPEN_FORMULA_TAG);
+ }
+
+ private void serializeAtomicFormula(AtomicFormula atomicFormula, XmlSerializer xmlSerializer)
+ throws IOException {
+ if (atomicFormula == null) {
+ return;
+ }
+ xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG);
+ serializeValue(KEY_TAG, String.valueOf(atomicFormula.getKey()), xmlSerializer);
+ if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) {
+ serializeValue(VALUE_TAG,
+ ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer);
+ } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) {
+ serializeValue(OPERATOR_TAG,
+ String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()),
+ xmlSerializer);
+ serializeValue(VALUE_TAG,
+ String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()),
+ xmlSerializer);
+ } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) {
+ serializeValue(VALUE_TAG,
+ String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()),
+ xmlSerializer);
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Invalid atomic formula type: %s", atomicFormula.getClass()));
+ }
+ xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG);
+ }
+
+ private void serializeValue(String tag, String value, XmlSerializer xmlSerializer)
+ throws IOException {
+ if (value == null) {
+ return;
+ }
+ xmlSerializer.startTag(NAMESPACE, tag);
+ xmlSerializer.text(value);
+ xmlSerializer.endTag(NAMESPACE, tag);
}
}
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
deleted file mode 100644
index 2e21fa67a967..000000000000
--- a/services/core/java/com/android/server/location/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsLocationCoarseTestCases"
- },
- {
- "name": "CtsLocationNoneTestCases"
- }
- ]
-} \ No newline at end of file
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 53d922b6da9f..f23ac343881f 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -721,6 +721,10 @@ public class SyntheticPasswordManager {
}
return VerifyCredentialResponse.fromGateKeeperResponse(response);
} else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
+ if (!isWeaverAvailable()) {
+ Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
+ return VerifyCredentialResponse.ERROR;
+ }
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
byte[] pwdToken = computePasswordToken(userCredential, pwd);
int weaverSlot = persistentData.userId;
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 626bf1cc361b..51a0df33bc65 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -84,9 +84,9 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
mCallback = callback;
}
- public void selectRoute(String packageName, String routeId) {
+ public void requestSelectRoute(String packageName, String routeId, int seq) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(packageName, routeId);
+ mActiveConnection.requestSelectRoute(packageName, routeId, seq);
updateBinding();
}
}
@@ -328,9 +328,9 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
mClient.dispose();
}
- public void selectRoute(String packageName, String routeId) {
+ public void requestSelectRoute(String packageName, String routeId, int seq) {
try {
- mProvider.selectRoute(packageName, routeId);
+ mProvider.requestSelectRoute(packageName, routeId, seq);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2e97f6a559d6..adfb9cb0964e 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -29,10 +29,13 @@ import android.media.IMediaRouter2Manager;
import android.media.IMediaRouterClient;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRouter2;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -60,6 +63,7 @@ import java.util.Set;
class MediaRouter2ServiceImpl {
private static final String TAG = "MR2ServiceImpl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final long ROUTE_SELECTION_REQUEST_TIMEOUT_MS = 5000L;
private final Context mContext;
private final Object mLock = new Object();
@@ -72,6 +76,8 @@ class MediaRouter2ServiceImpl {
private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
@GuardedBy("mLock")
private int mCurrentUserId = -1;
+ @GuardedBy("mLock")
+ private int mSelectRouteRequestSequenceNumber = 0;
MediaRouter2ServiceImpl(Context context) {
mContext = context;
@@ -189,12 +195,12 @@ class MediaRouter2ServiceImpl {
}
}
- public void selectRoute2(@NonNull IMediaRouter2Client client,
+ public void requestSelectRoute2(@NonNull IMediaRouter2Client client,
@Nullable MediaRoute2Info route) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- selectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+ requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -375,24 +381,38 @@ class MediaRouter2ServiceImpl {
}
}
- private void selectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
- clientRecord.mSelectedRoute = route;
+ clientRecord.mSelectingRoute = route;
UserHandler handler = clientRecord.mUserRecord.mHandler;
//TODO: Handle transfer instead of unselect and select
if (oldRoute != null) {
- handler.sendMessage(
- obtainMessage(UserHandler::unselectRoute, handler, clientRecord,
- oldRoute));
+ handler.sendMessage(obtainMessage(
+ UserHandler::unselectRoute, handler, clientRecord.mPackageName, oldRoute));
}
if (route != null) {
- handler.sendMessage(
- obtainMessage(UserHandler::selectRoute, handler, clientRecord, route));
+ final int seq = mSelectRouteRequestSequenceNumber;
+ mSelectRouteRequestSequenceNumber++;
+
+ handler.sendMessage(obtainMessage(
+ UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
+ route, seq));
+
+ // Remove all previous timeout messages
+ for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
+ clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
+ }
+ clientRecord.mSelectRouteSequenceNumbers.clear();
+
+ // When the request is not handled in timeout, set the client's route to default.
+ Message timeoutMsg = obtainMessage(UserHandler::handleRouteSelectionTimeout,
+ handler, clientRecord.mPackageName, route);
+ timeoutMsg.what = seq; // Make the message cancelable.
+ handler.sendMessageDelayed(timeoutMsg, ROUTE_SELECTION_REQUEST_TIMEOUT_MS);
+ clientRecord.mSelectRouteSequenceNumbers.add(seq);
}
- handler.sendMessage(
- obtainMessage(UserHandler::updateClientUsage, handler, clientRecord));
}
}
@@ -473,6 +493,11 @@ class MediaRouter2ServiceImpl {
userRecord.mHandler, manager));
for (ClientRecord clientRecord : userRecord.mClientRecords) {
+ // TODO: Do not use updateClientUsage since it updates all managers.
+ // Instead, Notify only to the manager that is currently being registered.
+
+ // TODO: UserRecord <-> ClientRecord, why do they reference each other?
+ // How about removing mUserRecord from clientRecord?
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::updateClientUsage,
clientRecord.mUserRecord.mHandler, clientRecord));
@@ -494,12 +519,13 @@ class MediaRouter2ServiceImpl {
String packageName, MediaRoute2Info route) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord != null) {
- ClientRecord clientRecord = managerRecord.mUserRecord.findClientRecord(packageName);
+ ClientRecord clientRecord =
+ managerRecord.mUserRecord.findClientRecordLocked(packageName);
if (clientRecord == null) {
Slog.w(TAG, "Ignoring route selection for unknown client.");
}
if (clientRecord != null && managerRecord.mTrusted) {
- selectRoute2Locked(clientRecord, route);
+ requestSelectRoute2Locked(clientRecord, route);
}
}
}
@@ -598,7 +624,7 @@ class MediaRouter2ServiceImpl {
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
- ClientRecord findClientRecord(String packageName) {
+ ClientRecord findClientRecordLocked(String packageName) {
for (ClientRecord clientRecord : mClientRecords) {
if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
return clientRecord;
@@ -611,12 +637,15 @@ class MediaRouter2ServiceImpl {
class ClientRecord {
public final UserRecord mUserRecord;
public final String mPackageName;
+ public final List<Integer> mSelectRouteSequenceNumbers;
public List<String> mControlCategories;
+ public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
ClientRecord(UserRecord userRecord, String packageName) {
mUserRecord = userRecord;
mPackageName = packageName;
+ mSelectRouteSequenceNumbers = new ArrayList<>();
mControlCategories = Collections.emptyList();
}
}
@@ -752,6 +781,15 @@ class MediaRouter2ServiceImpl {
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
+ // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
+ // Make this method to be called.
+ public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+ String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
+ sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
+ controlHints, seq));
+ }
+
private void updateProvider(MediaRoute2ProviderProxy provider) {
int providerIndex = getProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
@@ -834,24 +872,104 @@ class MediaRouter2ServiceImpl {
return -1;
}
- private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void updateSelectedRoute(MediaRoute2ProviderProxy provider,
+ String clientPackageName, MediaRoute2Info selectedRoute, Bundle controlHints,
+ int seq) {
+ if (selectedRoute == null
+ || !TextUtils.equals(clientPackageName, selectedRoute.getClientPackageName())) {
+ Log.w(TAG, "Ignoring route selection which has non-matching clientPackageName.");
+ return;
+ }
+
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return;
+ }
+
+ ClientRecord clientRecord;
+ synchronized (service.mLock) {
+ clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
+ }
+ if (!(clientRecord instanceof Client2Record)) {
+ Log.w(TAG, "Ignoring route selection for unknown client.");
+ unselectRoute(clientPackageName, selectedRoute);
+ return;
+ }
+
+ if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
+ clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
+ Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
+ + clientRecord.mSelectingRoute + " route=" + selectedRoute);
+ unselectRoute(clientPackageName, selectedRoute);
+ return;
+ }
+ clientRecord.mSelectingRoute = null;
+ clientRecord.mSelectedRoute = selectedRoute;
+
+ notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+ selectedRoute,
+ MediaRouter2.SELECT_REASON_USER_SELECTED,
+ controlHints);
+ updateClientUsage(clientRecord);
+
+ // Remove the fallback route selection message.
+ removeMessages(seq);
+ }
+
+ private void handleRouteSelectionTimeout(String clientPackageName,
+ MediaRoute2Info selectingRoute) {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return;
+ }
+
+ ClientRecord clientRecord;
+ synchronized (service.mLock) {
+ clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
+ }
+ if (!(clientRecord instanceof Client2Record)) {
+ Log.w(TAG, "Ignoring fallback route selection for unknown client.");
+ return;
+ }
+
+ if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
+ clientRecord.mSelectingRoute.getUniqueId(), selectingRoute.getUniqueId())) {
+ Log.w(TAG, "Ignoring invalid selectFallbackRoute call. "
+ + "Current selectingRoute=" + clientRecord.mSelectingRoute
+ + " , original selectingRoute=" + selectingRoute);
+ return;
+ }
+
+ clientRecord.mSelectingRoute = null;
+ // TODO: When the default route is introduced, make mSelectedRoute always non-null.
+ MediaRoute2Info fallbackRoute = null;
+ clientRecord.mSelectedRoute = fallbackRoute;
+
+ notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+ fallbackRoute,
+ MediaRouter2.SELECT_REASON_FALLBACK,
+ Bundle.EMPTY /* controlHints */);
+ updateClientUsage(clientRecord);
+ }
+
+ private void requestSelectRoute(String clientPackageName, MediaRoute2Info route, int seq) {
if (route != null) {
MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
if (provider == null) {
Slog.w(TAG, "Ignoring to select route of unknown provider " + route);
} else {
- provider.selectRoute(clientRecord.mPackageName, route.getId());
+ provider.requestSelectRoute(clientPackageName, route.getId(), seq);
}
}
}
- private void unselectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void unselectRoute(String clientPackageName, MediaRoute2Info route) {
if (route != null) {
MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
if (provider == null) {
Slog.w(TAG, "Ignoring to unselect route of unknown provider " + route);
} else {
- provider.unselectRoute(clientRecord.mPackageName, route.getId());
+ provider.unselectRoute(clientPackageName, route.getId());
}
}
}
@@ -922,6 +1040,15 @@ class MediaRouter2ServiceImpl {
}
}
+ private void notifyRouteSelectedToClient(IMediaRouter2Client client,
+ MediaRoute2Info route, int reason, Bundle controlHints) {
+ try {
+ client.notifyRouteSelected(route, reason, controlHints);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify routes selected. Client probably died.", ex);
+ }
+ }
+
private void notifyRoutesAddedToClients(List<IMediaRouter2Client> clients,
List<MediaRoute2Info> routes) {
for (IMediaRouter2Client client : clients) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index afd92f61b9d3..ecc1abaa2cdf 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -459,8 +459,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void selectRoute2(IMediaRouter2Client client, MediaRoute2Info route) {
- mService2.selectRoute2(client, route);
+ public void requestSelectRoute2(IMediaRouter2Client client, MediaRoute2Info route) {
+ mService2.requestSelectRoute2(client, route);
}
// Binder call
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 99b1ef4a1d2e..f05b2bf9711f 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -16,8 +16,15 @@
package com.android.server.notification;
+import android.app.AlarmManager;
import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
import android.os.Handler;
import android.util.AtomicFile;
import android.util.Slog;
@@ -33,11 +40,15 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.concurrent.TimeUnit;
/**
* Provides an interface to write and query for notification history data for a user from a Protocol
@@ -52,32 +63,48 @@ public class NotificationHistoryDatabase {
private static final String TAG = "NotiHistoryDatabase";
private static final boolean DEBUG = NotificationManagerService.DBG;
private static final int HISTORY_RETENTION_DAYS = 2;
+ private static final int HISTORY_RETENTION_MS = 24 * 60 * 60 * 1000;
private static final long WRITE_BUFFER_INTERVAL_MS = 1000 * 60 * 20;
+ private static final String ACTION_HISTORY_DELETION =
+ NotificationHistoryDatabase.class.getSimpleName() + ".CLEANUP";
+ private static final int REQUEST_CODE_DELETION = 1;
+ private static final String SCHEME_DELETION = "delete";
+ private static final String EXTRA_KEY = "key";
+
+ private final Context mContext;
+ private final AlarmManager mAlarmManager;
private final Object mLock = new Object();
private Handler mFileWriteHandler;
@VisibleForTesting
// List of files holding history information, sorted newest to oldest
final LinkedList<AtomicFile> mHistoryFiles;
- private final GregorianCalendar mCal;
private final File mHistoryDir;
private final File mVersionFile;
// Current version of the database files schema
private int mCurrentVersion;
private final WriteBufferRunnable mWriteBufferRunnable;
+ private final FileAttrProvider mFileAttrProvider;
// Object containing posted notifications that have not yet been written to disk
@VisibleForTesting
NotificationHistory mBuffer;
- public NotificationHistoryDatabase(File dir) {
+ public NotificationHistoryDatabase(Context context, File dir,
+ FileAttrProvider fileAttrProvider) {
+ mContext = context;
+ mAlarmManager = context.getSystemService(AlarmManager.class);
mCurrentVersion = DEFAULT_CURRENT_VERSION;
mVersionFile = new File(dir, "version");
mHistoryDir = new File(dir, "history");
mHistoryFiles = new LinkedList<>();
- mCal = new GregorianCalendar();
mBuffer = new NotificationHistory();
mWriteBufferRunnable = new WriteBufferRunnable();
+ mFileAttrProvider = fileAttrProvider;
+
+ IntentFilter deletionFilter = new IntentFilter(ACTION_HISTORY_DELETION);
+ deletionFilter.addDataScheme(SCHEME_DELETION);
+ mContext.registerReceiver(mFileCleaupReceiver, deletionFilter);
}
public void init(Handler fileWriteHandler) {
@@ -105,7 +132,8 @@ public class NotificationHistoryDatabase {
}
// Sort with newest files first
- Arrays.sort(files, (lhs, rhs) -> Long.compare(rhs.lastModified(), lhs.lastModified()));
+ Arrays.sort(files, (lhs, rhs) -> Long.compare(mFileAttrProvider.getCreationTime(rhs),
+ mFileAttrProvider.getCreationTime(lhs)));
for (File file : files) {
mHistoryFiles.addLast(new AtomicFile(file));
@@ -197,31 +225,48 @@ public class NotificationHistoryDatabase {
}
/**
- * Remove any files that are too old.
+ * Remove any files that are too old and schedule jobs to clean up the rest
*/
public void prune(final int retentionDays, final long currentTimeMillis) {
synchronized (mLock) {
- mCal.setTimeInMillis(currentTimeMillis);
- mCal.add(Calendar.DATE, -1 * retentionDays);
-
- while (!mHistoryFiles.isEmpty()) {
- final AtomicFile currentOldestFile = mHistoryFiles.getLast();
- final long age = currentTimeMillis
- - currentOldestFile.getBaseFile().lastModified();
- if (age > mCal.getTimeInMillis()) {
+ GregorianCalendar retentionBoundary = new GregorianCalendar();
+ retentionBoundary.setTimeInMillis(currentTimeMillis);
+ retentionBoundary.add(Calendar.DATE, -1 * retentionDays);
+
+ for (int i = mHistoryFiles.size() - 1; i >= 0; i--) {
+ final AtomicFile currentOldestFile = mHistoryFiles.get(i);
+ final long creationTime =
+ mFileAttrProvider.getCreationTime(currentOldestFile.getBaseFile());
+ if (creationTime <= retentionBoundary.getTimeInMillis()) {
if (DEBUG) {
Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
}
currentOldestFile.delete();
mHistoryFiles.removeLast();
} else {
- // all remaining files are newer than the cut off
- return;
+ // all remaining files are newer than the cut off; schedule jobs to delete
+ final long deletionTime = creationTime + (retentionDays * HISTORY_RETENTION_MS);
+ scheduleDeletion(currentOldestFile.getBaseFile(), deletionTime);
}
}
}
}
+ void scheduleDeletion(File file, long deletionTime) {
+ if (DEBUG) {
+ Slog.d(TAG, "Scheduling deletion for " + file.getName() + " at " + deletionTime);
+ }
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext,
+ REQUEST_CODE_DELETION,
+ new Intent(ACTION_HISTORY_DELETION)
+ .setData(new Uri.Builder().scheme(SCHEME_DELETION)
+ .appendPath(file.getAbsolutePath()).build())
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(EXTRA_KEY, file.getAbsolutePath()),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, deletionTime, pi);
+ }
+
private void writeLocked(AtomicFile file, NotificationHistory notifications)
throws IOException {
FileOutputStream fos = file.startWrite();
@@ -245,6 +290,25 @@ public class NotificationHistoryDatabase {
}
}
+ private final BroadcastReceiver mFileCleaupReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ if (ACTION_HISTORY_DELETION.equals(action)) {
+ try {
+ final String filePath = intent.getStringExtra(EXTRA_KEY);
+ AtomicFile fileToDelete = new AtomicFile(new File(filePath));
+ fileToDelete.delete();
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to delete notification history file", e);
+ }
+ }
+ }
+ };
+
private final class WriteBufferRunnable implements Runnable {
@Override
public void run() {
@@ -277,10 +341,7 @@ public class NotificationHistoryDatabase {
// Remove packageName entries from pending history
mBuffer.removeNotificationsFromWrite(mPkg);
- // Remove packageName entries from files on disk, and rewrite them to disk
- // Since we sort by modified date, we have to update the files oldest to newest to
- // maintain the original ordering
- Iterator<AtomicFile> historyFileItr = mHistoryFiles.descendingIterator();
+ Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator();
while (historyFileItr.hasNext()) {
final AtomicFile af = historyFileItr.next();
try {
@@ -297,4 +358,24 @@ public class NotificationHistoryDatabase {
}
}
}
+
+ public static final class NotificationHistoryFileAttrProvider implements
+ NotificationHistoryDatabase.FileAttrProvider {
+ final static String TAG = "NotifHistoryFileDate";
+
+ public long getCreationTime(File file) {
+ try {
+ BasicFileAttributes attr = Files.readAttributes(FileSystems.getDefault().getPath(
+ file.getAbsolutePath()), BasicFileAttributes.class);
+ return attr.creationTime().to(TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Slog.w(TAG, "Cannot read creation data for file; using file name");
+ return Long.valueOf(file.getName());
+ }
+ }
+ }
+
+ interface FileAttrProvider {
+ long getCreationTime(File file);
+ }
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 0a3c58150689..cbbf2a0ee04b 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -757,7 +757,7 @@ public class PreferencesHelper implements RankingConfig {
clearLockedFieldsLocked(channel);
channel.setImportanceLockedByOEM(r.oemLockedImportance);
if (!channel.isImportanceLockedByOEM()) {
- if (r.futureOemLockedChannels.remove(channel.getId())) {
+ if (r.oemLockedChannels.contains(channel.getId())) {
channel.setImportanceLockedByOEM(true);
}
}
@@ -952,11 +952,10 @@ public class PreferencesHelper implements RankingConfig {
NotificationChannel channel = r.channels.get(channelId);
if (channel != null) {
channel.setImportanceLockedByOEM(true);
- } else {
- // if this channel shows up in the future, make sure it'll
- // be locked immediately
- r.futureOemLockedChannels.add(channelId);
}
+ // Also store the locked channels on the record, so they aren't
+ // temporarily lost when data is cleared on the package
+ r.oemLockedChannels.add(channelId);
}
}
}
@@ -1528,9 +1527,9 @@ public class PreferencesHelper implements RankingConfig {
pw.print(" oemLocked=");
pw.print(r.oemLockedImportance);
}
- if (!r.futureOemLockedChannels.isEmpty()) {
+ if (!r.oemLockedChannels.isEmpty()) {
pw.print(" futureLockedChannels=");
- pw.print(r.futureOemLockedChannels);
+ pw.print(r.oemLockedChannels);
}
pw.println();
for (NotificationChannel channel : r.channels.values()) {
@@ -1940,7 +1939,7 @@ public class PreferencesHelper implements RankingConfig {
// these fields are loaded on boot from a different source of truth and so are not
// written to notification policy xml
boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
- List<String> futureOemLockedChannels = new ArrayList<>();
+ List<String> oemLockedChannels = new ArrayList<>();
boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
Delegate delegate = null;
diff --git a/services/core/java/com/android/server/pm/InstallSource.java b/services/core/java/com/android/server/pm/InstallSource.java
index 990eba15234e..0541797523a4 100644
--- a/services/core/java/com/android/server/pm/InstallSource.java
+++ b/services/core/java/com/android/server/pm/InstallSource.java
@@ -18,8 +18,6 @@ package com.android.server.pm;
import android.annotation.Nullable;
-import com.android.internal.util.IndentingPrintWriter;
-
import java.util.Objects;
/**
@@ -31,13 +29,25 @@ final class InstallSource {
* An instance of InstallSource representing an absence of knowledge of the source of
* a package. Used in preference to null.
*/
- static final InstallSource EMPTY = new InstallSource(null, null, false);
+ static final InstallSource EMPTY = new InstallSource(null, null, null, false);
+
+ /** We also memoize this case because it is common - all un-updated system apps. */
+ private static final InstallSource EMPTY_ORPHANED = new InstallSource(null, null, null, true);
/** The package that requested the installation, if known. */
@Nullable
final String initiatingPackageName;
/**
+ * The package on behalf of which the initiating package requested the installation, if any.
+ * For example if a downloaded APK is installed via the Package Installer this could be the
+ * app that performed the download. This value is provided by the initiating package and not
+ * verified by the framework.
+ */
+ @Nullable
+ final String originatingPackageName;
+
+ /**
* Package name of the app that installed this package (the installer of record). Note that
* this may be modified.
*/
@@ -48,47 +58,55 @@ final class InstallSource {
final boolean isOrphaned;
static InstallSource create(@Nullable String initiatingPackageName,
- @Nullable String installerPackageName) {
- return create(initiatingPackageName, installerPackageName, false);
+ @Nullable String originatingPackageName, @Nullable String installerPackageName,
+ boolean isOrphaned) {
+ return createInternal(
+ intern(initiatingPackageName),
+ intern(originatingPackageName),
+ intern(installerPackageName),
+ isOrphaned);
}
- static InstallSource create(@Nullable String initiatingPackageName,
- @Nullable String installerPackageName, boolean isOrphaned) {
- if (initiatingPackageName == null && installerPackageName == null && !isOrphaned) {
- return EMPTY;
+ private static InstallSource createInternal(@Nullable String initiatingPackageName,
+ @Nullable String originatingPackageName, @Nullable String installerPackageName,
+ boolean isOrphaned) {
+ if (initiatingPackageName == null && originatingPackageName == null
+ && installerPackageName == null) {
+ return isOrphaned ? EMPTY_ORPHANED : EMPTY;
}
- return new InstallSource(
- initiatingPackageName == null ? null : initiatingPackageName.intern(),
- installerPackageName == null ? null : installerPackageName.intern(),
- isOrphaned);
+ return new InstallSource(initiatingPackageName, originatingPackageName,
+ installerPackageName, isOrphaned);
}
private InstallSource(@Nullable String initiatingPackageName,
- @Nullable String installerPackageName, boolean isOrphaned) {
+ @Nullable String originatingPackageName, @Nullable String installerPackageName,
+ boolean isOrphaned) {
this.initiatingPackageName = initiatingPackageName;
- this.isOrphaned = isOrphaned;
+ this.originatingPackageName = originatingPackageName;
this.installerPackageName = installerPackageName;
- }
-
- void dump(IndentingPrintWriter pw) {
- pw.printPair("installerPackageName", installerPackageName);
- pw.printPair("installInitiatingPackageName", initiatingPackageName);
+ this.isOrphaned = isOrphaned;
}
/**
* Return an InstallSource the same as this one except with the specified installerPackageName.
*/
InstallSource setInstallerPackage(String installerPackageName) {
- return Objects.equals(installerPackageName, this.installerPackageName) ? this
- : create(initiatingPackageName, installerPackageName, isOrphaned);
+ if (Objects.equals(installerPackageName, this.installerPackageName)) {
+ return this;
+ }
+ return createInternal(initiatingPackageName, originatingPackageName,
+ intern(installerPackageName), isOrphaned);
}
/**
* Return an InstallSource the same as this one except with the specified value for isOrphaned.
*/
InstallSource setIsOrphaned(boolean isOrphaned) {
- return isOrphaned == this.isOrphaned ? this
- : create(initiatingPackageName, installerPackageName, isOrphaned);
+ if (isOrphaned == this.isOrphaned) {
+ return this;
+ }
+ return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
+ isOrphaned);
}
/**
@@ -102,6 +120,7 @@ final class InstallSource {
boolean modified = false;
String initiatingPackageName = this.initiatingPackageName;
+ String originatingPackageName = this.originatingPackageName;
String installerPackageName = this.installerPackageName;
boolean isOrphaned = this.isOrphaned;
@@ -109,14 +128,25 @@ final class InstallSource {
initiatingPackageName = null;
modified = true;
}
+ if (packageName.equals(originatingPackageName)) {
+ originatingPackageName = null;
+ modified = true;
+ }
if (packageName.equals(installerPackageName)) {
installerPackageName = null;
isOrphaned = true;
modified = true;
}
- return modified
- ? create(initiatingPackageName, installerPackageName, isOrphaned)
- : this;
+ if (!modified) {
+ return this;
+ }
+ return createInternal(initiatingPackageName, originatingPackageName, installerPackageName,
+ isOrphaned);
+ }
+
+ @Nullable
+ private static String intern(@Nullable String packageName) {
+ return packageName == null ? null : packageName.intern();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed2bb3d53649..6564e71936eb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -512,6 +512,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ String originatingPackageName = null;
+ if (params.originatingUid != SessionParams.UID_UNKNOWN
+ && params.originatingUid != callingUid) {
+ String[] packages = mPm.getPackagesForUid(params.originatingUid);
+ if (packages != null && packages.length > 0) {
+ // Choose an arbitrary representative package in the case of a shared UID.
+ originatingPackageName = packages[0];
+ }
+ }
+
if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) {
params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
} else {
@@ -624,7 +634,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
InstallSource installSource = InstallSource.create(installerPackageName,
- requestedInstallerPackageName);
+ originatingPackageName, requestedInstallerPackageName, false);
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
installSource, params, createdMillis,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index feb1271d8c79..631df0ff9845 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -148,6 +148,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String ATTR_INSTALLER_UID = "installerUid";
private static final String ATTR_INITIATING_PACKAGE_NAME =
"installInitiatingPackageName";
+ private static final String ATTR_ORIGINATING_PACKAGE_NAME =
+ "installOriginatingPackageName";
private static final String ATTR_CREATED_MILLIS = "createdMillis";
private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
@@ -1227,7 +1229,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
mInstallerUid = newOwnerAppInfo.uid;
- mInstallSource = InstallSource.create(packageName, packageName);
+ mInstallSource = InstallSource.create(packageName, null, packageName, false);
}
// Persist the fact that we've sealed ourselves to prevent
@@ -2336,7 +2338,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
pw.printPair("userId", userId);
pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
- mInstallSource.dump(pw);
+ pw.printPair("installerPackageName", mInstallSource.installerPackageName);
+ pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
+ pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
pw.printPair("mInstallerUid", mInstallerUid);
pw.printPair("createdMillis", createdMillis);
pw.printPair("updatedMillis", updatedMillis);
@@ -2420,6 +2424,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
mInstallSource.initiatingPackageName);
+ writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
+ mInstallSource.originatingPackageName);
writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
if (stageDir != null) {
@@ -2527,6 +2533,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
final String installInitiatingPackageName =
readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
+ final String installOriginatingPackageName =
+ readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
@@ -2619,7 +2627,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
- installerPackageName);
+ installOriginatingPackageName, installerPackageName, false);
return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, stagingManager, sessionId, userId, installerUid,
installSource, params, createdMillis, stageDir, stageCid,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f1c84b8701ba..525d3578ccff 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -115,6 +115,7 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
@@ -438,8 +439,14 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- private void setParamsSize(InstallParams params, String inPath) {
- if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
+ private void setParamsSize(InstallParams params, List<String> inPaths) {
+ if (params.sessionParams.sizeBytes != -1 || STDIN_PATH.equals(inPaths.get(0))) {
+ return;
+ }
+
+ long sessionSize = 0;
+
+ for (String inPath : inPaths) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
if (fd == null) {
getErrPrintWriter().println("Error: Can't open file: " + inPath);
@@ -449,8 +456,8 @@ class PackageManagerShellCommand extends ShellCommand {
ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0);
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
null, null);
- params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
- pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor()));
+ sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
+ params.sessionParams.abiOverride, fd.getFileDescriptor());
} catch (PackageParserException | IOException e) {
getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath);
throw new IllegalArgumentException(
@@ -462,6 +469,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
}
+ params.sessionParams.setSize(sessionSize);
}
/**
* Displays the package file for a package.
@@ -1148,23 +1156,44 @@ class PackageManagerShellCommand extends ShellCommand {
private int runInstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final InstallParams params = makeInstallParams();
- final String inPath = getNextArg();
- setParamsSize(params, inPath);
+ ArrayList<String> inPaths = getRemainingArgs();
+ if (inPaths.isEmpty()) {
+ inPaths.add(STDIN_PATH);
+ }
+
+ final boolean hasSplits = inPaths.size() > 1;
+
+ if (STDIN_PATH.equals(inPaths.get(0))) {
+ if (hasSplits) {
+ pw.println("Error: can't specify SPLIT(s) along with STDIN");
+ return 1;
+ }
+ if (params.sessionParams.sizeBytes == -1) {
+ pw.println("Error: must either specify a package size or an APK file");
+ return 1;
+ }
+ }
+
+ final boolean isApex =
+ (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+ if (isApex && hasSplits) {
+ pw.println("Error: can't specify SPLIT(s) for APEX");
+ return 1;
+ }
+
+ setParamsSize(params, inPaths);
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
- if (inPath == null && params.sessionParams.sizeBytes == -1) {
- pw.println("Error: must either specify a package size or an APK file");
- return 1;
- }
- final boolean isApex =
- (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
- String splitName = "base." + (isApex ? "apex" : "apk");
- if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
- false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
- return 1;
+ for (String inPath : inPaths) {
+ String splitName = hasSplits ? (new File(inPath)).getName()
+ : "base." + (isApex ? "apex" : "apk");
+ if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
+ false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
}
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
@@ -1283,12 +1312,12 @@ class PackageManagerShellCommand extends ShellCommand {
final int sessionId = Integer.parseInt(getNextArg());
- final String splitName = getNextArg();
- if (splitName == null) {
+ ArrayList<String> splitNames = getRemainingArgs();
+ if (splitNames.isEmpty()) {
pw.println("Error: split name not specified");
return 1;
}
- return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
+ return doRemoveSplits(sessionId, splitNames, true /*logSuccess*/);
}
private int runInstallExisting() throws RemoteException {
@@ -1731,6 +1760,15 @@ class PackageManagerShellCommand extends ShellCommand {
return 0;
}
+ private ArrayList<String> getRemainingArgs() {
+ ArrayList<String> args = new ArrayList<>();
+ String arg;
+ while ((arg = getNextArg()) != null) {
+ args.add(arg);
+ }
+ return args;
+ }
+
private static class SnapshotRuntimeProfileCallback
extends ISnapshotRuntimeProfileCallback.Stub {
private boolean mSuccess = false;
@@ -1802,9 +1840,9 @@ class PackageManagerShellCommand extends ShellCommand {
}
// if a split is specified, just remove it and not the whole package
- final String splitName = getNextArg();
- if (splitName != null) {
- return runRemoveSplit(packageName, splitName);
+ ArrayList<String> splitNames = getRemainingArgs();
+ if (!splitNames.isEmpty()) {
+ return runRemoveSplits(packageName, splitNames);
}
userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
@@ -1852,7 +1890,8 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
+ private int runRemoveSplits(String packageName, Collection<String> splitNames)
+ throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
@@ -1861,7 +1900,7 @@ class PackageManagerShellCommand extends ShellCommand {
doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
boolean abandonSession = true;
try {
- if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
+ if (doRemoveSplits(sessionId, splitNames, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
@@ -2945,14 +2984,17 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
+ private int doRemoveSplits(int sessionId, Collection<String> splitNames, boolean logSuccess)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
- session.removeSplit(splitName);
+
+ for (String splitName : splitNames) {
+ session.removeSplit(splitName);
+ }
if (logSuccess) {
pw.println("Success");
@@ -3237,9 +3279,9 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
pw.println(" [--apex] [--wait TIMEOUT]");
- pw.println(" [PATH|-]");
- pw.println(" Install an application. Must provide the apk data to install, either as a");
- pw.println(" file path or '-' to read from stdin. Options are:");
+ pw.println(" [PATH [SPLIT...]|-]");
+ pw.println(" Install an application. Must provide the apk data to install, either as");
+ pw.println(" file path(s) or '-' to read from stdin. Options are:");
pw.println(" -R: disallow replacement of existing application");
pw.println(" -t: allow test packages");
pw.println(" -i: specify package name of installer owning the app");
@@ -3293,6 +3335,9 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" will be read from stdin. Options are:");
pw.println(" -S: size in bytes of package, required for stdin");
pw.println("");
+ pw.println(" install-remove SESSION_ID SPLIT...");
+ pw.println(" Mark SPLIT(s) as removed in the given install session.");
+ pw.println("");
pw.println(" install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
pw.println(" Add one or more session IDs to a multi-package session.");
pw.println("");
@@ -3317,9 +3362,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println("");
pw.println(" move-primary-storage [internal|UUID]");
pw.println("");
- pw.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE [SPLIT]");
+ pw.println(" uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE]");
+ pw.println(" PACKAGE [SPLIT...]");
pw.println(" Remove the given package name from the system. May remove an entire app");
- pw.println(" if no SPLIT name is specified, otherwise will remove only the split of the");
+ pw.println(" if no SPLIT names specified, otherwise will remove only the splits of the");
pw.println(" given app. Options are:");
pw.println(" -k: keep the data and cache directories around after package removal.");
pw.println(" --user: remove the app from the given user.");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 4fca91a83724..12548918bfcc 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -209,6 +209,8 @@ public final class PackageSetting extends PackageSettingBase {
long sourceToken = proto.start(PackageProto.INSTALL_SOURCE);
proto.write(PackageProto.InstallSourceProto.INITIATING_PACKAGE_NAME,
installSource.initiatingPackageName);
+ proto.write(PackageProto.InstallSourceProto.ORIGINATING_PACKAGE_NAME,
+ installSource.originatingPackageName);
proto.end(sourceToken);
}
writeUsersInfoToProto(proto, PackageProto.USERS);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 66c77f583c57..5f3650c21b8e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2848,6 +2848,9 @@ public final class Settings {
if (installSource.initiatingPackageName != null) {
serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
}
+ if (installSource.originatingPackageName != null) {
+ serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
+ }
if (pkg.volumeUuid != null) {
serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
}
@@ -3605,6 +3608,7 @@ public final class Settings {
String systemStr = null;
String installerPackageName = null;
String isOrphaned = null;
+ String installOriginatingPackageName = null;
String installInitiatingPackageName = null;
String volumeUuid = null;
String categoryHintString = null;
@@ -3653,6 +3657,7 @@ public final class Settings {
installerPackageName = parser.getAttributeValue(null, "installer");
isOrphaned = parser.getAttributeValue(null, "isOrphaned");
installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
+ installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
categoryHintString = parser.getAttributeValue(null, "categoryHint");
if (categoryHintString != null) {
@@ -3808,7 +3813,8 @@ public final class Settings {
if (packageSetting != null) {
packageSetting.uidError = "true".equals(uidError);
packageSetting.installSource = InstallSource.create(
- installInitiatingPackageName, installerPackageName, "true".equals(isOrphaned));
+ installInitiatingPackageName, installOriginatingPackageName,
+ installerPackageName, "true".equals(isOrphaned));
packageSetting.volumeUuid = volumeUuid;
packageSetting.categoryHint = categoryHint;
packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f7b60c25ce4a..e8798ffa3720 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -22,6 +22,9 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "PackageManagerShellCommandTest"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index b3f1867fdb06..cc5aec2e113e 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -314,9 +314,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
case ArtManager.PROFILE_APPS :
return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
case ArtManager.PROFILE_BOOT_IMAGE:
+ // The device config property overrides the system property version.
+ boolean profileBootClassPath = SystemProperties.getBoolean(
+ "persist.device_config.runtime_native_boot.profilebootclasspath",
+ SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false));
return (Build.IS_USERDEBUG || Build.IS_ENG) &&
SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
- SystemProperties.getBoolean("dalvik.vm.profilebootimage", false);
+ profileBootClassPath;
default:
throw new IllegalArgumentException("Invalid profile type:" + profileType);
}
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index c779ebf4a995..3aafd5e35dc4 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -403,7 +403,7 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn
public String getStatus() {
return mContext.getString(
com.android.internal.R.string.bugreport_status,
- Build.VERSION.RELEASE,
+ Build.VERSION.RELEASE_OR_CODENAME,
Build.ID);
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 01250db9c5c6..1f37fafc3442 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -213,15 +213,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public Rect getDisplayFrameLw();
/**
- * Retrieve the frame of the area inside the overscan region of the
- * display that this window was last laid out in. Must be called with the
- * window manager lock held.
- *
- * @return Rect The rectangle holding the display overscan frame.
- */
- public Rect getOverscanFrameLw();
-
- /**
* Retrieve the frame of the content area that this window was last
* laid out in. This is the area in which the content of the window
* should be placed. It will be smaller than the display frame to
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f78d2639df1a..add0b01f1879 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,8 +19,6 @@ package com.android.server.policy.keyguard;
import android.app.ActivityManager;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.security.keystore.IKeystoreService;
import android.util.Slog;
import com.android.internal.policy.IKeyguardService;
@@ -53,16 +51,11 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
private final LockPatternUtils mLockPatternUtils;
private final StateCallback mCallback;
- IKeystoreService mKeystoreService;
-
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
mCallback = callback;
- mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.security.keystore"));
-
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -95,23 +88,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
mIsShowing = showing;
mCallback.onShowingChanged();
- int retry = 2;
- while (retry > 0) {
- try {
- mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
- break;
- } catch (RemoteException e) {
- if (retry == 2) {
- Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
- + " -> refreshing service token and retrying");
- mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.security.keystore"));
- } else {
- Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
- }
- --retry;
- }
- }
}
@Override // Binder interface
@@ -123,10 +99,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
mCurrentUserId = userId;
}
- private synchronized int getCurrentUser() {
- return mCurrentUserId;
- }
-
@Override // Binder interface
public void onInputRestrictedStateChanged(boolean inputRestricted) {
mInputRestricted = inputRestricted;
diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
index 8431ae4aeb98..c1eacce1f304 100644
--- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
@@ -15,28 +15,22 @@
*/
package com.android.server.stats;
-import android.annotation.Nullable;
-import android.os.FileUtils;
-import android.util.Slog;
+import static android.os.Process.PROC_OUT_STRING;
-import com.android.internal.annotations.VisibleForTesting;
+import android.annotation.Nullable;
+import android.os.Process;
-import java.io.File;
-import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.function.BiConsumer;
final class ProcfsMemoryUtil {
- private static final String TAG = "ProcfsMemoryUtil";
-
- private static final Pattern STATUS_MEMORY_STATS =
- Pattern.compile(String.join(
- ".*",
- "Uid:\\s*(\\d+)\\s*",
- "VmHWM:\\s*(\\d+)\\s*kB",
- "VmRSS:\\s*(\\d+)\\s*kB",
- "RssAnon:\\s*(\\d+)\\s*kB",
- "VmSwap:\\s*(\\d+)\\s*kB"), Pattern.DOTALL);
+ private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING };
+ private static final String[] STATUS_KEYS = new String[] {
+ "Uid:",
+ "VmHWM:",
+ "VmRSS:",
+ "RssAnon:",
+ "VmSwap:"
+ };
private ProcfsMemoryUtil() {}
@@ -46,30 +40,21 @@ final class ProcfsMemoryUtil {
*/
@Nullable
static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
- return parseMemorySnapshotFromStatus(readFile("/proc/" + pid + "/status"));
- }
-
- @VisibleForTesting
- @Nullable
- static MemorySnapshot parseMemorySnapshotFromStatus(String contents) {
- if (contents.isEmpty()) {
+ long[] output = new long[STATUS_KEYS.length];
+ output[0] = -1;
+ Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output);
+ if (output[0] == -1 || (output[3] == 0 && output[4] == 0)) {
+ // Could not open file or anon rss / swap are 0 indicating the process is in a zombie
+ // state.
return null;
}
- try {
- final Matcher matcher = STATUS_MEMORY_STATS.matcher(contents);
- if (matcher.find()) {
- final MemorySnapshot snapshot = new MemorySnapshot();
- snapshot.uid = Integer.parseInt(matcher.group(1));
- snapshot.rssHighWaterMarkInKilobytes = Integer.parseInt(matcher.group(2));
- snapshot.rssInKilobytes = Integer.parseInt(matcher.group(3));
- snapshot.anonRssInKilobytes = Integer.parseInt(matcher.group(4));
- snapshot.swapInKilobytes = Integer.parseInt(matcher.group(5));
- return snapshot;
- }
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Failed to parse value", e);
- }
- return null;
+ final MemorySnapshot snapshot = new MemorySnapshot();
+ snapshot.uid = (int) output[0];
+ snapshot.rssHighWaterMarkInKilobytes = (int) output[1];
+ snapshot.rssInKilobytes = (int) output[2];
+ snapshot.anonRssInKilobytes = (int) output[3];
+ snapshot.swapInKilobytes = (int) output[4];
+ return snapshot;
}
/**
@@ -78,30 +63,26 @@ final class ProcfsMemoryUtil {
* Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
* if the file is not available.
*/
- public static String readCmdlineFromProcfs(int pid) {
- return parseCmdline(readFile("/proc/" + pid + "/cmdline"));
- }
-
- /**
- * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
- *
- * Parsing is required to strip anything after the first null byte.
- */
- @VisibleForTesting
- static String parseCmdline(String contents) {
- int firstNullByte = contents.indexOf("\0");
- if (firstNullByte == -1) {
- return contents;
+ static String readCmdlineFromProcfs(int pid) {
+ String[] cmdline = new String[1];
+ if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) {
+ return "";
}
- return contents.substring(0, firstNullByte);
+ return cmdline[0];
}
- private static String readFile(String path) {
- try {
- final File file = new File(path);
- return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */);
- } catch (IOException e) {
- return "";
+ static void forEachPid(BiConsumer<Integer, String> func) {
+ int[] pids = new int[1024];
+ pids = Process.getPids("/proc", pids);
+ for (int pid : pids) {
+ if (pid < 0) {
+ return;
+ }
+ String cmdline = readCmdlineFromProcfs(pid);
+ if (cmdline.isEmpty()) {
+ continue;
+ }
+ func.accept(pid, cmdline);
}
}
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 2d36a0dd1be4..72a1b9df3b3c 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -18,6 +18,8 @@ package com.android.server.storage;
import android.Manifest;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,7 +27,12 @@ import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.IVold;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.os.storage.VolumeInfo;
import android.provider.MediaStore;
import android.service.storage.ExternalStorageService;
@@ -47,27 +54,41 @@ public final class StorageSessionController {
private final Object mLock = new Object();
private final Context mContext;
- private final Callback mCallback;
- @GuardedBy("mLock")
- private ComponentName mExternalStorageServiceComponent;
@GuardedBy("mLock")
private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
+ private final boolean mIsFuseEnabled;
+
+ private volatile ComponentName mExternalStorageServiceComponent;
+ private volatile String mExternalStorageServicePackageName;
+ private volatile int mExternalStorageServiceAppId;
+ private volatile boolean mIsResetting;
- public StorageSessionController(Context context, Callback callback) {
+ public StorageSessionController(Context context, boolean isFuseEnabled) {
mContext = Preconditions.checkNotNull(context);
- mCallback = Preconditions.checkNotNull(callback);
+ mIsFuseEnabled = isFuseEnabled;
}
/**
- * Starts a storage session associated with {@code deviceFd} for {@code vol}.
- * Does nothing if a session is already started or starting. If the user associated with
- * {@code vol} is not yet ready, the session will be retried {@link #onUserStarted}.
+ * Creates a storage session associated with {@code deviceFd} for {@code vol}. Sessions can be
+ * started with {@link #onVolumeReady} and removed with {@link #onVolumeUnmount} or
+ * {@link #onVolumeRemove}.
*
- * A session must be ended with {@link #endSession} when no longer required.
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * @throws IllegalStateException if a session has already been created for {@code vol}
*/
- public void onVolumeMounted(int userId, FileDescriptor deviceFd, VolumeInfo vol) {
+ public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol) {
+ if (!shouldHandle(vol)) {
+ return;
+ }
+
+ Slog.i(TAG, "On volume mount " + vol);
+
+ String sessionId = vol.getId();
+ int userId = vol.getMountUserId();
+
if (deviceFd == null) {
- Slog.w(TAG, "Null device fd. Session not started for " + vol);
+ Slog.w(TAG, "Null fd. Session not started for vol: " + vol);
return;
}
@@ -82,136 +103,320 @@ public final class StorageSessionController {
}
if ("/dev/null".equals(realPath)) {
- Slog.i(TAG, "Volume ready for use: " + vol);
+ Slog.i(TAG, "Volume ready for use with id: " + sessionId);
return;
}
synchronized (mLock) {
StorageUserConnection connection = mConnections.get(userId);
if (connection == null) {
- Slog.i(TAG, "Creating new session for vol: " + vol);
connection = new StorageUserConnection(mContext, userId, this);
mConnections.put(userId, connection);
}
- try {
- Slog.i(TAG, "Starting session for vol: " + vol);
- connection.startSession(deviceFd, vol);
- } catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to start session for vol: " + vol, e);
+ Slog.i(TAG, "Creating session with id: " + sessionId);
+ connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd));
+ }
+ }
+
+ /**
+ * Starts a storage session associated with {@code vol} after {@link #onVolumeMount}.
+ *
+ * Subsequent calls will attempt to start the storage session, but does nothing if already
+ * started. If the user associated with {@code vol} is not yet ready, all pending sesssions
+ * can be restarted with {@link onUnlockUser}.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * Blocks until the session is started or fails
+ *
+ * @throws ExternalStorageServiceException if the session fails to start
+ */
+ public void onVolumeReady(VolumeInfo vol) throws ExternalStorageServiceException {
+ if (!shouldHandle(vol)) {
+ return;
+ }
+
+ Slog.i(TAG, "On volume ready " + vol);
+ String sessionId = vol.getId();
+
+ StorageUserConnection connection = null;
+ synchronized (mLock) {
+ connection = mConnections.get(vol.getMountUserId());
+ if (connection == null) {
+ Slog.i(TAG, "Volume ready but no associated connection");
+ return;
}
}
+
+ connection.initSession(sessionId, vol.getPath().getPath(),
+ vol.getInternalPath().getPath());
+
+ if (isReady()) {
+ connection.startSession(sessionId);
+ } else {
+ Slog.i(TAG, "Controller not initialised, session not started " + sessionId);
+ }
}
/**
- * Ends a storage session for {@code vol}. Does nothing if the session is already
- * ended or ending. Ending a session discards all resources associated with that session.
+ * Removes and returns the {@link StorageUserConnection} for {@code vol}.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * @return the connection that was removed or {@code null} if nothing was removed
*/
- public void onVolumeUnmounted(int userId, VolumeInfo vol) {
+ @Nullable
+ public StorageUserConnection onVolumeRemove(VolumeInfo vol) {
+ if (!shouldHandle(vol)) {
+ return null;
+ }
+
+ Slog.i(TAG, "On volume remove " + vol);
+ String sessionId = vol.getId();
+ int userId = vol.getMountUserId();
+
synchronized (mLock) {
StorageUserConnection connection = mConnections.get(userId);
if (connection != null) {
- Slog.i(TAG, "Ending session for vol: " + vol);
- try {
- if (connection.endSession(vol)) {
- mConnections.remove(userId);
- }
- } catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to end session for vol: " + vol, e);
- }
+ Slog.i(TAG, "Removed session for vol with id: " + sessionId);
+ connection.removeSession(sessionId);
+ return connection;
} else {
- Slog.w(TAG, "Session already ended for vol: " + vol);
+ Slog.w(TAG, "Session already removed for vol with id: " + sessionId);
+ return null;
}
}
}
- /** Restarts all sessions for {@code userId}. */
- public void onUserStarted(int userId) {
- synchronized (mLock) {
- StorageUserConnection connection = mConnections.get(userId);
- if (connection != null) {
+
+ /**
+ * Removes a storage session for {@code vol} and waits for exit.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * Any errors are ignored
+ *
+ * Call {@link #onVolumeRemove} to remove the connection without waiting for exit
+ */
+ public void onVolumeUnmount(VolumeInfo vol) {
+ StorageUserConnection connection = onVolumeRemove(vol);
+
+ Slog.i(TAG, "On volume unmount " + vol);
+ if (connection != null) {
+ String sessionId = vol.getId();
+
+ if (isReady()) {
try {
- Slog.i(TAG, "Restarting all sessions for user: " + userId);
- connection.startAllSessions();
+ connection.removeSessionAndWait(sessionId);
} catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to start all sessions", e);
+ Slog.e(TAG, "Failed to end session for vol with id: " + sessionId, e);
}
} else {
- // TODO(b/135341433): What does this mean in multi-user
+ Slog.i(TAG, "Controller not initialised, session not ended " + sessionId);
}
}
}
- /** Ends all sessions for {@code userId}. */
- public void onUserRemoved(int userId) {
+ /**
+ * Restarts all sessions for {@code userId}.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ *
+ * This call blocks and waits for all sessions to be started, however any failures when starting
+ * a session will be ignored.
+ */
+ public void onUnlockUser(int userId) throws ExternalStorageServiceException {
+ if (!shouldHandle(null)) {
+ return;
+ }
+
+ Slog.i(TAG, "On user unlock " + userId);
+ if (userId == 0) {
+ init();
+ }
+
+ StorageUserConnection connection = null;
synchronized (mLock) {
- StorageUserConnection connection = mConnections.get(userId);
- if (connection != null) {
+ connection = mConnections.get(userId);
+ }
+
+ if (connection != null) {
+ Slog.i(TAG, "Restarting all sessions for user: " + userId);
+ connection.startAllSessions();
+ } else {
+ Slog.w(TAG, "No connection found for user: " + userId);
+ }
+ }
+
+ /**
+ * Resets all sessions for all users and waits for exit. This may kill the
+ * {@link ExternalStorageservice} for a user if necessary to ensure all state has been reset.
+ *
+ * Does nothing if {@link #shouldHandle} is {@code false}
+ **/
+ public void onReset(IVold vold, Handler handler) {
+ if (!shouldHandle(null)) {
+ return;
+ }
+
+ if (!isReady()) {
+ synchronized (mLock) {
+ mConnections.clear();
+ }
+ return;
+ }
+
+ SparseArray<StorageUserConnection> connections = new SparseArray();
+ synchronized (mLock) {
+ mIsResetting = true;
+ Slog.i(TAG, "Started resetting external storage service...");
+ for (int i = 0; i < mConnections.size(); i++) {
+ connections.put(mConnections.keyAt(i), mConnections.valueAt(i));
+ }
+ }
+
+ for (int i = 0; i < connections.size(); i++) {
+ StorageUserConnection connection = connections.valueAt(i);
+ for (String sessionId : connection.getAllSessionIds()) {
try {
- Slog.i(TAG, "Ending all sessions for user: " + userId);
- connection.endAllSessions();
- mConnections.remove(userId);
- } catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to end all sessions", e);
+ Slog.i(TAG, "Unmounting " + sessionId);
+ vold.unmount(sessionId);
+ Slog.i(TAG, "Unmounted " + sessionId);
+ } catch (ServiceSpecificException | RemoteException e) {
+ // TODO(b/140025078): Hard reset vold?
+ Slog.e(TAG, "Failed to unmount volume: " + sessionId, e);
+ }
+
+ try {
+ Slog.i(TAG, "Exiting " + sessionId);
+ connection.removeSessionAndWait(sessionId);
+ Slog.i(TAG, "Exited " + sessionId);
+ } catch (IllegalStateException | ExternalStorageServiceException e) {
+ Slog.e(TAG, "Failed to exit session: " + sessionId
+ + ". Killing MediaProvider...", e);
+ // If we failed to confirm the session exited, it is risky to proceed
+ // We kill the ExternalStorageService as a last resort
+ killExternalStorageService(connections.keyAt(i));
+ break;
}
- } else {
- // TODO(b/135341433): What does this mean in multi-user
}
+ connection.close();
+ }
+
+ handler.removeCallbacksAndMessages(null);
+ synchronized (mLock) {
+ mConnections.clear();
+ mIsResetting = false;
+ Slog.i(TAG, "Finished resetting external storage service");
}
}
+ private void init() throws ExternalStorageServiceException {
+ Slog.i(TAG, "Initialialising...");
+ ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
+ MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_SYSTEM_ONLY);
+ if (provider == null) {
+ throw new ExternalStorageServiceException("No valid MediaStore provider found");
+ }
+
+ mExternalStorageServicePackageName = provider.applicationInfo.packageName;
+ mExternalStorageServiceAppId = UserHandle.getAppId(provider.applicationInfo.uid);
+
+ Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
+ intent.setPackage(mExternalStorageServicePackageName);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+ if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+ throw new ExternalStorageServiceException(
+ "No valid ExternalStorageService component found");
+ }
+
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
+ .equals(serviceInfo.permission)) {
+ throw new ExternalStorageServiceException(name.flattenToShortString()
+ + " does not require permission "
+ + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
+ }
+
+ mExternalStorageServiceComponent = name;
+ }
+
/** Returns the {@link ExternalStorageService} component name. */
@Nullable
public ComponentName getExternalStorageServiceComponentName() {
- synchronized (mLock) {
- if (mExternalStorageServiceComponent == null) {
- ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
- MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_SYSTEM_ONLY);
-
- if (provider == null) {
- Slog.e(TAG, "No valid MediaStore provider found.");
- }
- String packageName = provider.applicationInfo.packageName;
-
- Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
- intent.setPackage(packageName);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
- if (resolveInfo == null || resolveInfo.serviceInfo == null) {
- Slog.e(TAG, "No valid ExternalStorageService component found.");
- return null;
- }
+ return mExternalStorageServiceComponent;
+ }
- ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
- if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
- .equals(serviceInfo.permission)) {
- Slog.e(TAG, name.flattenToShortString() + " does not require permission "
- + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
- return null;
- }
- mExternalStorageServiceComponent = name;
- }
- return mExternalStorageServiceComponent;
+ private void killExternalStorageService(int userId) {
+ IActivityManager am = ActivityManager.getService();
+ try {
+ am.killApplication(mExternalStorageServicePackageName, mExternalStorageServiceAppId,
+ userId, "storage_session_controller reset");
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to kill the ExtenalStorageService for user " + userId);
}
}
- /** Returns the {@link StorageManagerService} callback. */
- public Callback getCallback() {
- return mCallback;
+ /**
+ * Throws an {@link IllegalStateException} if {@code path} is not ready to be accessed by
+ * {@code userId}.
+ */
+ // TODO(b/144332951): This is not used because it is racy. Right after checking a path
+ // we can call into vold with that path and the FUSE daemon can go down. Improve or remove
+ public void checkPathReadyForUser(int userId, String path) {
+ if (!mIsFuseEnabled) {
+ return;
+ }
+
+ if (mIsResetting) {
+ throw new IllegalStateException("Connection resetting for user " + userId
+ + " with path " + path);
+ }
+
+ StorageUserConnection connection = null;
+ synchronized (mLock) {
+ connection = mConnections.get(userId);
+ }
+
+ if (connection == null) {
+ throw new IllegalStateException("Connection not ready for user " + userId
+ + " with path " + path);
+ }
+ connection.checkPathReady(path);
}
- /** Callback to listen to session events from the {@link StorageSessionController}. */
- public interface Callback {
- /** Called when a {@link StorageUserConnection} is disconnected. */
- void onUserDisconnected(int userId);
+ /**
+ * Returns {@code true} if {@code vol} is an emulated or public volume,
+ * {@code false} otherwise
+ **/
+ public static boolean isEmulatedOrPublic(VolumeInfo vol) {
+ return vol.type == VolumeInfo.TYPE_EMULATED || vol.type == VolumeInfo.TYPE_PUBLIC;
}
- /** Exception thrown when communication with the {@link ExternalStorageService}. */
+ /** Exception thrown when communication with the {@link ExternalStorageService} fails. */
public static class ExternalStorageServiceException extends Exception {
public ExternalStorageServiceException(Throwable cause) {
super(cause);
}
+
+ public ExternalStorageServiceException(String message) {
+ super(message);
+ }
+
+ public ExternalStorageServiceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private boolean shouldHandle(@Nullable VolumeInfo vol) {
+ return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+ }
+
+ private boolean isReady() {
+ return mExternalStorageServiceComponent != null;
}
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index ff9c900958ea..24b56a48900b 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -33,29 +33,31 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
import android.os.RemoteCallback;
-import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.storage.VolumeInfo;
import android.service.storage.ExternalStorageService;
import android.service.storage.IExternalStorageService;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
- * for a user and manages storage sessions represented by a {@link Session}.
+ * for a user and manages storage sessions associated with mounted volumes.
*/
public final class StorageUserConnection {
private static final String TAG = "StorageUserConnection";
+ private static final int REMOTE_TIMEOUT_SECONDS = 15;
private final Object mLock = new Object();
private final Context mContext;
@@ -70,68 +72,188 @@ public final class StorageUserConnection {
mSessionController = controller;
}
- /** Starts a session for a user */
- public void startSession(FileDescriptor deviceFd, VolumeInfo vol)
- throws ExternalStorageServiceException {
- String sessionId = vol.getId();
- String upperPath = vol.getPath().getPath();
- String lowerPath = vol.getInternalPath().getPath();
- Slog.i(TAG, "Starting session with id: " + sessionId + " and upperPath: " + upperPath
- + " and lowerPath: " + lowerPath);
- Session session = new Session(sessionId, deviceFd, upperPath, lowerPath);
+ /**
+ * Creates and stores a storage {@link Session}.
+ *
+ * Created sessions must be initialised with {@link #initSession} before starting with
+ * {@link #startSession}.
+ *
+ * They must also be cleaned up with {@link #removeSession}.
+ *
+ * @throws IllegalArgumentException if a {@code Session} with {@code sessionId} already exists
+ */
+ public void createSession(String sessionId, ParcelFileDescriptor pfd) {
+ Preconditions.checkNotNull(sessionId);
+ Preconditions.checkNotNull(pfd);
+
+ synchronized (mLock) {
+ Preconditions.checkArgument(!mSessions.containsKey(sessionId));
+ mSessions.put(sessionId, new Session(sessionId, pfd));
+ }
+ }
+
+ /**
+ * Initialise a storage {@link Session}.
+ *
+ * Initialised sessions can be started with {@link #startSession}.
+ *
+ * They must also be cleaned up with {@link #removeSession}.
+ *
+ * @throws IllegalArgumentException if {@code sessionId} does not exist or is initialised
+ */
+ public void initSession(String sessionId, String upperPath, String lowerPath) {
+ synchronized (mLock) {
+ Session session = mSessions.get(sessionId);
+ if (session == null) {
+ throw new IllegalStateException("Failed to initialise non existent session. Id: "
+ + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath);
+ } else if (session.isInitialisedLocked()) {
+ throw new IllegalStateException("Already initialised session. Id: "
+ + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath);
+ } else {
+ session.upperPath = upperPath;
+ session.lowerPath = lowerPath;
+ Slog.i(TAG, "Initialised session: " + session);
+ }
+ }
+ }
+
+ /**
+ * Starts an already created storage {@link Session} for {@code sessionId}.
+ *
+ * It is safe to call this multiple times, however if the session is already started,
+ * subsequent calls will be ignored.
+ *
+ * @throws ExternalStorageServiceException if the session failed to start
+ **/
+ public void startSession(String sessionId) throws ExternalStorageServiceException {
+ Session session;
+ synchronized (mLock) {
+ session = mSessions.get(sessionId);
+ }
+
+ prepareRemote();
synchronized (mLock) {
- // TODO(b/135341433): Ensure we don't replace a session without ending the previous
- mSessions.put(sessionId, session);
- // TODO(b/135341433): If this fails, maybe its at boot, how to handle if not boot?
mActiveConnection.startSessionLocked(session);
}
}
/**
- * Ends a session for a user.
+ * Removes a session without ending it or waiting for exit.
*
- * @return {@code true} if there are no more sessions for this user, {@code false} otherwise
+ * This should only be used if the session has certainly been ended because the volume was
+ * unmounted or the user running the session has been stopped. Otherwise, wait for session
+ * with {@link #waitForExit}.
**/
- public boolean endSession(VolumeInfo vol) throws ExternalStorageServiceException {
+ public Session removeSession(String sessionId) {
synchronized (mLock) {
- Session session = mSessions.remove(vol.getId());
+ Session session = mSessions.remove(sessionId);
if (session != null) {
- mActiveConnection.endSessionLocked(session);
- mSessions.remove(session.sessionId);
- }
- boolean isAllSessionsEnded = mSessions.isEmpty();
- if (isAllSessionsEnded) {
- mActiveConnection.close();
+ session.close();
+ return session;
}
- return isAllSessionsEnded;
+ return null;
+ }
+ }
+
+
+ /**
+ * Removes a session and waits for exit
+ *
+ * @throws ExternalStorageServiceException if the session may not have exited
+ **/
+ public void removeSessionAndWait(String sessionId) throws ExternalStorageServiceException {
+ Session session = removeSession(sessionId);
+ if (session == null) {
+ Slog.i(TAG, "No session found for id: " + sessionId);
+ return;
+ }
+
+ Slog.i(TAG, "Waiting for session end " + session + " ...");
+ prepareRemote();
+ synchronized (mLock) {
+ mActiveConnection.endSessionLocked(session);
}
}
- /** Starts all available sessions for a user */
- public void startAllSessions() throws ExternalStorageServiceException {
+ /** Starts all available sessions for a user without blocking. Any failures will be ignored. */
+ public void startAllSessions() {
+ try {
+ prepareRemote();
+ } catch (ExternalStorageServiceException e) {
+ Slog.e(TAG, "Failed to start all sessions for user: " + mUserId, e);
+ return;
+ }
+
synchronized (mLock) {
+ Slog.i(TAG, "Starting " + mSessions.size() + " sessions for user: " + mUserId + "...");
for (Session session : mSessions.values()) {
- mActiveConnection.startSessionLocked(session);
+ try {
+ mActiveConnection.startSessionLocked(session);
+ } catch (IllegalStateException | ExternalStorageServiceException e) {
+ // TODO: Don't crash process? We could get into process crash loop
+ Slog.e(TAG, "Failed to start " + session, e);
+ }
}
}
}
- /** Ends all available sessions for a user */
- public void endAllSessions() throws ExternalStorageServiceException {
+ /**
+ * Closes the connection to the {@link ExternalStorageService}. The connection will typically
+ * be restarted after close.
+ */
+ public void close() {
+ mActiveConnection.close();
+ }
+
+ /** Throws an {@link IllegalArgumentException} if {@code path} is not ready for access */
+ public void checkPathReady(String path) {
synchronized (mLock) {
for (Session session : mSessions.values()) {
- mActiveConnection.endSessionLocked(session);
- mSessions.remove(session.sessionId);
+ if (session.upperPath != null && path.startsWith(session.upperPath)) {
+ if (mActiveConnection.isActiveLocked(session)) {
+ return;
+ }
+ }
+ }
+ throw new IllegalStateException("Path not ready " + path);
+ }
+ }
+
+ /** Returns all created sessions. */
+ public Set<String> getAllSessionIds() {
+ synchronized (mLock) {
+ return new HashSet<>(mSessions.keySet());
+ }
+ }
+
+ private void prepareRemote() throws ExternalStorageServiceException {
+ try {
+ waitForLatch(mActiveConnection.bind(), "remote_prepare_user " + mUserId);
+ } catch (IllegalStateException | TimeoutException e) {
+ throw new ExternalStorageServiceException("Failed to prepare remote", e);
+ }
+ }
+
+ private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
+ try {
+ if (!latch.await(REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+ // TODO(b/140025078): Call ActivityManager ANR API?
+ throw new TimeoutException("Latch wait for " + reason + " elapsed");
}
- mActiveConnection.close();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Latch wait for " + reason + " interrupted");
}
}
private final class ActiveConnection implements AutoCloseable {
// Lifecycle connection to the external storage service, needed to unbind.
- // We should only try to bind if mServiceConnection is null.
- // Non-null indicates we are connected or connecting.
@GuardedBy("mLock") @Nullable private ServiceConnection mServiceConnection;
+ // True if we are connecting, either bound or binding
+ // False && mRemote != null means we are connected
+ // False && mRemote == null means we are neither connecting nor connected
+ @GuardedBy("mLock") @Nullable private boolean mIsConnecting;
// Binder object representing the external storage service.
// Non-null indicates we are connected
@GuardedBy("mLock") @Nullable private IExternalStorageService mRemote;
@@ -141,58 +263,72 @@ public final class StorageUserConnection {
// (and clear the exception state) with the same lock which we hold during
// the entire transaction, there is no risk of race.
@GuardedBy("mLock") @Nullable private ParcelableException mLastException;
+ // Not guarded by any lock intentionally and non final because we cannot
+ // reset latches so need to create a new one after one use
+ private CountDownLatch mLatch;
@Override
public void close() {
+ ServiceConnection oldConnection = null;
synchronized (mLock) {
- if (mServiceConnection != null) {
- mContext.unbindService(mServiceConnection);
- }
+ Slog.i(TAG, "Closing connection for user " + mUserId);
+ mIsConnecting = false;
+ oldConnection = mServiceConnection;
mServiceConnection = null;
mRemote = null;
}
+
+ if (oldConnection != null) {
+ mContext.unbindService(oldConnection);
+ }
+ }
+
+ public boolean isActiveLocked(Session session) {
+ if (!session.isInitialisedLocked()) {
+ Slog.i(TAG, "Session not initialised " + session);
+ return false;
+ }
+
+ if (mRemote == null) {
+ throw new IllegalStateException("Valid session with inactive connection");
+ }
+ return true;
}
public void startSessionLocked(Session session) throws ExternalStorageServiceException {
- if (mServiceConnection == null || mRemote == null) {
- if (mServiceConnection == null) {
- // Not bound
- bindLocked();
- } // else we are binding. In any case when we bind we'll re-start all sessions
+ if (!isActiveLocked(session)) {
return;
}
CountDownLatch latch = new CountDownLatch(1);
- try {
+ try (ParcelFileDescriptor dupedPfd = session.pfd.dup()) {
mRemote.startSession(session.sessionId,
FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
- new ParcelFileDescriptor(session.deviceFd), session.upperPath,
- session.lowerPath, new RemoteCallback(result ->
+ dupedPfd, session.upperPath, session.lowerPath, new RemoteCallback(result ->
setResultLocked(latch, result)));
-
- } catch (RemoteException e) {
- throw new ExternalStorageServiceException(e);
+ waitForLatch(latch, "start_session " + session);
+ maybeThrowExceptionLocked();
+ } catch (Exception e) {
+ throw new ExternalStorageServiceException("Failed to start session: " + session, e);
}
- waitAndReturnResultLocked(latch);
}
public void endSessionLocked(Session session) throws ExternalStorageServiceException {
- if (mRemote == null) {
- // TODO(b/135341433): This assumes if there is no connection, there are no
- // session resources held. Need to document in the ExternalStorageService
- // API that implementors should end all sessions and clean up resources
- // when the binding is lost, onDestroy?
+ session.close();
+ if (!isActiveLocked(session)) {
+ // Nothing to end, not started yet
return;
}
CountDownLatch latch = new CountDownLatch(1);
try {
mRemote.endSession(session.sessionId, new RemoteCallback(result ->
- setResultLocked(latch, result)));
- } catch (RemoteException e) {
- throw new ExternalStorageServiceException(e);
+ setResultLocked(latch, result)));
+ waitForLatch(latch, "end_session " + session);
+ maybeThrowExceptionLocked();
+ } catch (Exception e) {
+ throw new ExternalStorageServiceException("Failed to end session: " + session, e);
}
- waitAndReturnResultLocked(latch);
}
private void setResultLocked(CountDownLatch latch, Bundle result) {
@@ -200,36 +336,38 @@ public final class StorageUserConnection {
latch.countDown();
}
- private void waitAndReturnResultLocked(CountDownLatch latch)
- throws ExternalStorageServiceException {
- try {
- // TODO(b/140025078): Call ActivityManager ANR API?
- latch.await(20, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException(
- "Interrupted while waiting for ExternalStorageService result");
- }
+ private void maybeThrowExceptionLocked() throws IOException {
if (mLastException != null) {
+ ParcelableException lastException = mLastException;
mLastException = null;
try {
- mLastException.maybeRethrow(IOException.class);
+ lastException.maybeRethrow(IOException.class);
} catch (IOException e) {
- throw new ExternalStorageServiceException(e);
+ throw e;
}
- throw new RuntimeException(mLastException);
+ throw new RuntimeException(lastException);
}
- mLastException = null;
}
- private void bindLocked() {
+ public CountDownLatch bind() throws ExternalStorageServiceException {
ComponentName name = mSessionController.getExternalStorageServiceComponentName();
if (name == null) {
- Slog.i(TAG, "Not ready to bind to the ExternalStorageService for user " + mUserId);
- return;
+ // Not ready to bind
+ throw new ExternalStorageServiceException(
+ "Not ready to bind to the ExternalStorageService for user " + mUserId);
}
- ServiceConnection connection = new ServiceConnection() {
+ synchronized (mLock) {
+ if (mRemote != null || mIsConnecting) {
+ // Connected or connecting (bound or binding)
+ // Will wait on a latch that will countdown when we connect, unless we are
+ // connected and the latch has already countdown, yay!
+ return mLatch;
+ } // else neither connected nor connecting
+
+ mLatch = new CountDownLatch(1);
+ mIsConnecting = true;
+ mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Slog.i(TAG, "Service: [" + name + "] connected. User [" + mUserId + "]");
@@ -255,65 +393,81 @@ public final class StorageUserConnection {
@Override
public void onNullBinding(ComponentName name) {
- // Should never happen. Service returned null from #onBind.
Slog.wtf(TAG, "Service: [" + name + "] is null. User [" + mUserId + "]");
}
private void handleConnection(IBinder service) {
synchronized (mLock) {
- if (mServiceConnection != null) {
+ if (mIsConnecting) {
mRemote = IExternalStorageService.Stub.asInterface(service);
- } else {
- Slog.wtf(TAG, "Service connected without a connection object??");
+ mIsConnecting = false;
+ mLatch.countDown();
+ // Separate thread so we don't block the main thead
+ return;
}
}
-
- try {
- startAllSessions();
- } catch (ExternalStorageServiceException e) {
- Slog.e(TAG, "Failed to start all sessions", e);
- }
+ Slog.wtf(TAG, "Connection closed to the ExternalStorageService for user "
+ + mUserId);
}
private void handleDisconnection() {
- close();
// Clear all sessions because we will need a new device fd since
// StorageManagerService will reset the device mount state and #startSession
// will be called for any required mounts.
- synchronized (mLock) {
- mSessions.clear();
- }
// Notify StorageManagerService so it can restart all necessary sessions
- mSessionController.getCallback().onUserDisconnected(mUserId);
+ close();
+ new Thread(StorageUserConnection.this::startAllSessions).start();
}
};
+ }
Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
- // TODO(b/135341433): Verify required service flags BIND_IMPORTANT?
- if (mContext.bindServiceAsUser(new Intent().setComponent(name), connection,
- Context.BIND_AUTO_CREATE, UserHandle.of(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);
- mServiceConnection = connection;
- // Reset the remote, we will set when we connect
- mRemote = null;
+ return mLatch;
} else {
- Slog.w(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
+ synchronized (mLock) {
+ mIsConnecting = false;
+ }
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
}
}
}
- private static final class Session {
+ private static final class Session implements AutoCloseable {
public final String sessionId;
- public final FileDescriptor deviceFd;
- public final String lowerPath;
- public final String upperPath;
+ public final ParcelFileDescriptor pfd;
+ @GuardedBy("mLock")
+ public String lowerPath;
+ @GuardedBy("mLock")
+ public String upperPath;
- Session(String sessionId, FileDescriptor deviceFd, String upperPath,
- String lowerPath) {
+ Session(String sessionId, ParcelFileDescriptor pfd) {
this.sessionId = sessionId;
- this.upperPath = upperPath;
- this.lowerPath = lowerPath;
- this.deviceFd = deviceFd;
+ this.pfd = pfd;
+ }
+
+ @Override
+ public void close() {
+ try {
+ pfd.close();
+ } catch (IOException e) {
+ Slog.i(TAG, "Failed to close session: " + this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[SessionId: " + sessionId + ". UpperPath: " + upperPath + ". LowerPath: "
+ + lowerPath + "]";
+ }
+
+ @GuardedBy("mLock")
+ public boolean isInitialisedLocked() {
+ return !TextUtils.isEmpty(upperPath) && !TextUtils.isEmpty(lowerPath);
}
}
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 4d0788f7fdbd..7d905bae4491 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -120,7 +120,9 @@ public final class TextClassificationManagerService extends ITextClassifierServi
synchronized (mManagerService.mLock) {
UserState userState = mManagerService.peekUserStateLocked(userId);
if (userState != null) {
- userState.mConnection.cleanupService();
+ if (userState.mConnection != null) {
+ userState.mConnection.cleanupService();
+ }
mManagerService.mUserStates.remove(userId);
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 7408dd40b5ca..5f5cd3c46117 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.security.KeyStore;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -135,6 +136,33 @@ public class TrustManagerService extends SystemService {
@GuardedBy("mUserIsTrusted")
private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
+ /**
+ * Stores the locked state for users on the device. There are three different type of users
+ * which are handled slightly differently:
+ * <ul>
+ * <li> Users with real keyguard
+ * These are users who can be switched to ({@link UserInfo#supportsSwitchToByUser()}). Their
+ * locked state is derived by a combination of user secure state, keyguard state, trust agent
+ * decision and biometric authentication result. These are updated via
+ * {@link #refreshDeviceLockedForUser(int)} and result stored in {@link #mDeviceLockedForUser}.
+ * <li> Managed profiles with unified challenge
+ * Managed profile with unified challenge always shares the same locked state as their parent,
+ * so their locked state is not recorded in {@link #mDeviceLockedForUser}. Instead,
+ * {@link ITrustManager#isDeviceLocked(int)} always resolves their parent user handle and
+ * queries its locked state instead.
+ * <li> Managed profiles with separate challenge
+ * Locked state for profile with separate challenge is determined by other parts of the
+ * framework (mostly PowerManager) and pushed to TrustManagerService via
+ * {@link ITrustManager#setDeviceLockedForUser(int, boolean)}. Although in a corner case when
+ * the profile has a separate but empty challenge, setting its {@link #mDeviceLockedForUser} to
+ * {@code false} is actually done by {@link #refreshDeviceLockedForUser(int)}.
+ * </ul>
+ * TODO: Rename {@link ITrustManager#setDeviceLockedForUser(int, boolean)} to
+ * {@code setDeviceLockedForProfile} to better reflect its purpose. Unifying
+ * {@code setDeviceLockedForProfile} and {@link #setDeviceLockedForUser} would also be nice.
+ * At the moment they both update {@link #mDeviceLockedForUser} but have slightly different
+ * side-effects: one notifies trust agents while the other sends out a broadcast.
+ */
@GuardedBy("mDeviceLockedForUser")
private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
@@ -601,6 +629,10 @@ public class TrustManagerService extends SystemService {
}
}
+ /**
+ * Update the user's locked state. Only applicable to users with a real keyguard
+ * ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles.
+ */
private void refreshDeviceLockedForUser(int userId) {
if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle,"
@@ -661,6 +693,15 @@ public class TrustManagerService extends SystemService {
}
if (changed) {
dispatchDeviceLocked(userId, locked);
+
+ KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+ // Also update the user's profiles who have unified challenge, since they
+ // share the same unlocked state (see {@link #isDeviceLocked(int)})
+ for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
+ if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+ KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
+ }
+ }
}
}
@@ -1194,6 +1235,10 @@ public class TrustManagerService extends SystemService {
return "0x" + Integer.toHexString(i);
}
+ /**
+ * Changes the lock status for the given user. This is only applicable to managed profiles,
+ * other users should be handled by Keyguard.
+ */
@Override
public void setDeviceLockedForUser(int userId, boolean locked) {
enforceReportPermission();
@@ -1204,6 +1249,9 @@ public class TrustManagerService extends SystemService {
synchronized (mDeviceLockedForUser) {
mDeviceLockedForUser.put(userId, locked);
}
+
+ KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+
if (locked) {
try {
ActivityManager.getService().notifyLockedProfile(userId);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 86c8dc57557c..ebfc65e5d1e5 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -180,6 +180,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
mDisplayContent.reconfigureDisplayLocked();
onRequestedOverrideConfigurationChanged(
mDisplayContent.getRequestedOverrideConfiguration());
+ mService.mWindowManager.mDisplayNotificationController.dispatchDisplayAdded(this);
}
void onDisplayChanged() {
@@ -213,7 +214,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
if (position == POSITION_BOTTOM) {
position = 0;
} else if (toTop) {
- position = mStacks.size();
+ position = getChildCount();
}
if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
+ " to displayId=" + mDisplayId + " position=" + position);
@@ -253,7 +254,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
void positionChildAtTop(ActivityStack stack, boolean includingParents,
String updateLastFocusedStackReason) {
- positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason);
+ positionChildAt(stack, getChildCount(), includingParents, updateLastFocusedStackReason);
}
void positionChildAtBottom(ActivityStack stack) {
@@ -288,7 +289,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
// we are looking for top focusable stack. The condition {@code wasContained} restricts the
// preferred stack is set only when moving an existing stack to top instead of adding a new
// stack that may be too early (e.g. in the middle of launching or reparenting).
- if (wasContained && position >= mStacks.size() - 1 && stack.isFocusableAndVisible()) {
+ if (wasContained && position >= getChildCount() - 1 && stack.isFocusableAndVisible()) {
mPreferredTopFocusableStack = stack;
} else if (mPreferredTopFocusableStack == stack) {
mPreferredTopFocusableStack = null;
@@ -314,14 +315,14 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
- int position = mStacks.size();
+ int position = getChildCount();
if (stack.inPinnedWindowingMode()) {
// Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
// just return the candidate position.
return Math.min(position, candidatePosition);
}
while (position > 0) {
- final ActivityStack targetStack = mStacks.get(position - 1);
+ final ActivityStack targetStack = getChildAt(position - 1);
if (!targetStack.isAlwaysOnTop()) {
// We reached a stack that isn't always-on-top.
break;
@@ -336,8 +337,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
<T extends ActivityStack> T getStack(int stackId) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (stack.mStackId == stackId) {
return (T) stack;
}
@@ -362,8 +363,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
return (T) mSplitScreenPrimaryStack;
}
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (stack.isCompatible(windowingMode, activityType)) {
return (T) stack;
}
@@ -403,7 +404,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
* @see #getOrCreateStack(int, int, boolean)
*/
<T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
+ @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
boolean onTop) {
// First preference is the windowing mode in the activity options if set.
int windowingMode = (options != null)
@@ -489,8 +490,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
return mPreferredTopFocusableStack;
}
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (stack.isFocusableAndVisible()) {
return stack;
}
@@ -504,8 +505,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
ActivityStack candidate = null;
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (ignoreCurrent && stack == currentFocus) {
continue;
}
@@ -560,8 +561,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
boolean allResumedActivitiesComplete() {
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord r = mStacks.get(stackNdx).getResumedActivity();
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityRecord r = getChildAt(stackNdx).getResumedActivity();
if (r != null && !r.isState(RESUMED)) {
return false;
}
@@ -587,8 +588,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
*/
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
boolean someActivityPaused = false;
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mStacks.get(stackNdx);
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null
&& (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
@@ -652,8 +653,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
final ArrayList<ActivityStack> stacks = new ArrayList<>();
for (int j = windowingModes.length - 1 ; j >= 0; --j) {
final int windowingMode = windowingModes[j];
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (!stack.isActivityTypeStandardOrUndefined()) {
continue;
}
@@ -680,8 +681,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
final ArrayList<ActivityStack> stacks = new ArrayList<>();
for (int j = activityTypes.length - 1 ; j >= 0; --j) {
final int activityType = activityTypes[j];
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
if (stack.getActivityType() == activityType) {
stacks.add(stack);
}
@@ -752,8 +753,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
mService.deferWindowLayout();
try {
// Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack otherStack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = getChildAt(i);
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
@@ -781,8 +782,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
mService.deferWindowLayout();
try {
// Adjust the windowing mode of any affected by split-screen to split-screen secondary.
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack otherStack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = getChildAt(i);
if (otherStack == mSplitScreenPrimaryStack
|| !otherStack.affectedBySplitScreenResize()) {
continue;
@@ -850,7 +851,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
* @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
*/
int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable TaskRecord task, int activityType) {
+ @Nullable Task task, int activityType) {
// First preference if the windowing mode in the activity options if set.
int windowingMode = (options != null)
@@ -881,12 +882,12 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
*
* @param windowingMode The windowing-mode to validate.
* @param r The {@link ActivityRecord} to check against.
- * @param task The {@link TaskRecord} to check against.
+ * @param task The {@link Task} to check against.
* @param activityType An activity type.
* @return The provided windowingMode or the closest valid mode which is appropriate.
*/
- int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r,
- @Nullable TaskRecord task, int activityType) {
+ int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+ int activityType) {
// Make sure the windowing mode we are trying to use makes sense for what is supported.
boolean supportsMultiWindow = mService.mSupportsMultiWindow;
boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
@@ -930,7 +931,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
* some stacks are not focusable (e.g. PiP).
*/
ActivityStack getTopStack() {
- return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
+ return mStacks.isEmpty() ? null : getChildAt(getChildCount() - 1);
}
boolean isTopStack(ActivityStack stack) {
@@ -938,8 +939,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
boolean isTopNotPinnedStack(ActivityStack stack) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack current = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack current = getChildAt(i);
if (!current.inPinnedWindowingMode()) {
return current == stack;
}
@@ -948,8 +949,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
ActivityStack getTopStackInWindowingMode(int windowingMode) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack current = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack current = getChildAt(i);
if (windowingMode == current.getWindowingMode()) {
return current;
}
@@ -979,8 +980,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
// Look in other focusable stacks.
if (topRunning == null) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getChildAt(i);
// Only consider focusable stacks other than the current focused one.
if (stack == focusedStack || !stack.isFocusable()) {
continue;
@@ -1112,8 +1113,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
void onLockTaskPackagesUpdated() {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- mStacks.get(i).onLockTaskPackagesUpdated();
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ getChildAt(i).onLockTaskPackagesUpdated();
}
}
@@ -1165,7 +1166,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
@Override
public String toString() {
- return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+ return "ActivityDisplay={" + mDisplayId + " numStacks=" + getChildCount() + "}";
}
@Override
@@ -1224,10 +1225,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
mRootActivityContainer.mStackSupervisor.beginDeferResume();
try {
- int numStacks = mStacks.size();
+ int numStacks = getChildCount();
// Keep the order from bottom to top.
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack stack = mStacks.get(stackNdx);
+ final ActivityStack stack = getChildAt(stackNdx);
// Always finish non-standard type stacks.
if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
stack.finishAllActivitiesImmediately();
@@ -1244,8 +1245,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
// Stacks may be removed from this display. Ensure each stack will be processed and
// the loop will end.
- stackNdx -= numStacks - mStacks.size();
- numStacks = mStacks.size();
+ stackNdx -= numStacks - getChildCount();
+ numStacks = getChildCount();
}
} finally {
mRootActivityContainer.mStackSupervisor.endDeferResume();
@@ -1271,7 +1272,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
return;
}
- final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null;
+ final ActivityStack stack = getChildCount() == 1 ? getChildAt(0) : null;
if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
// Release this display if an empty home stack is the only thing left.
// Since it is the last stack, this display will be released along with the stack
@@ -1348,7 +1349,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
*/
ActivityStack getStackAbove(ActivityStack stack) {
final int stackIndex = mStacks.indexOf(stack) + 1;
- return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
+ return (stackIndex < getChildCount()) ? getChildAt(stackIndex) : null;
}
/**
@@ -1365,9 +1366,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
positionChildAtBottom(stack);
// Find the next position where the stack should be placed
- final int numStacks = mStacks.size();
+ final int numStacks = getChildCount();
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack s = mStacks.get(stackNdx);
+ final ActivityStack s = getChildAt(stackNdx);
if (s == stack) {
continue;
}
@@ -1447,9 +1448,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
return null;
}
- final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
+ final ArrayList<Task> tasks = mHomeStack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
+ final Task task = tasks.get(taskNdx);
if (!task.isActivityTypeHome()) {
continue;
}
@@ -1545,7 +1546,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
void removeAllTasks() {
for (int i = getChildCount() - 1; i >= 0; --i) {
final ActivityStack stack = getChildAt(i);
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final ArrayList<Task> tasks = stack.getAllTasks();
for (int j = tasks.size() - 1; j >= 0; --j) {
stack.removeChild(tasks.get(j), "removeAllTasks");
}
@@ -1553,7 +1554,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
+ pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getChildCount()
+ (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
final String myPrefix = prefix + " ";
if (mHomeStack != null) {
@@ -1577,8 +1578,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
public void dumpStacks(PrintWriter pw) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- pw.print(mStacks.get(i).mStackId);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ pw.print(getChildAt(i).mStackId);
if (i > 0) {
pw.print(",");
}
@@ -1601,8 +1602,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
} else {
proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
}
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mStacks.get(stackNdx);
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
stack.writeToProto(proto, STACKS, logLevel);
}
proto.end(token);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c506e274ef64..0a861ade2900 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -92,6 +92,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.server.LocalServices;
+
import java.util.concurrent.TimeUnit;
/**
@@ -171,7 +172,7 @@ class ActivityMetricsLogger {
switch (msg.what) {
case MSG_CHECK_VISIBILITY:
final SomeArgs args = (SomeArgs) msg.obj;
- checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
+ checkVisibility((Task) args.arg1, (ActivityRecord) args.arg2);
break;
}
}
@@ -536,7 +537,7 @@ class ActivityMetricsLogger {
if (info.launchedActivity != activityRecord) {
return;
}
- final TaskRecord t = activityRecord.getTaskRecord();
+ final Task t = activityRecord.getTask();
final SomeArgs args = SomeArgs.obtain();
args.arg1 = t;
args.arg2 = activityRecord;
@@ -544,17 +545,17 @@ class ActivityMetricsLogger {
}
/** @return {@code true} if the given task has an activity will be drawn. */
- private static boolean hasActivityToBeDrawn(TaskRecord t) {
+ private static boolean hasActivityToBeDrawn(Task t) {
for (int i = t.getChildCount() - 1; i >= 0; --i) {
final ActivityRecord r = t.getChildAt(i);
- if (r.visible && !r.mDrawn && !r.finishing) {
+ if (r.mVisibleRequested && !r.mDrawn && !r.finishing) {
return true;
}
}
return false;
}
- private void checkVisibility(TaskRecord t, ActivityRecord r) {
+ private void checkVisibility(Task t, ActivityRecord r) {
synchronized (mSupervisor.mService.mGlobalLock) {
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
@@ -984,7 +985,7 @@ class ActivityMetricsLogger {
}
} else if (info.startResult == START_SUCCESS
|| (info.startResult == START_TASK_TO_FRONT)) {
- // TaskRecord may still exist when cold launching an activity and the start
+ // Task may still exist when cold launching an activity and the start
// result will be set to START_TASK_TO_FRONT. Treat this as a COLD launch.
return TYPE_TRANSITION_COLD_LAUNCH;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 708e5a19bb0c..2162bdeead05 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -42,7 +42,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.activityTypeToString;
@@ -122,6 +121,7 @@ import static com.android.server.am.ActivityRecordProto.PROC_ID;
import static com.android.server.am.ActivityRecordProto.STATE;
import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
import static com.android.server.am.ActivityRecordProto.VISIBLE;
+import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED;
import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
@@ -173,12 +173,10 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_W
import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked;
import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN;
import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED;
-import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN;
+import static com.android.server.wm.AppWindowTokenProto.CLIENT_VISIBLE;
import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT;
import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT;
import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
-import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
-import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
import static com.android.server.wm.AppWindowTokenProto.IS_ANIMATING;
import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
@@ -193,6 +191,7 @@ import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED;
import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
+import static com.android.server.wm.AppWindowTokenProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW;
import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
@@ -417,7 +416,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private int logo; // resource identifier of activity's logo.
private int theme; // resource identifier of activity's theme.
private int windowFlags; // custom window flags for preview window.
- private TaskRecord task; // the task this is in.
+ private Task task; // the task this is in.
private long createTime = System.currentTimeMillis();
long lastVisibleTime; // last time this activity became visible
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
@@ -463,16 +462,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean keysPaused; // has key dispatching been paused for it?
int launchMode; // the launch mode activity attribute.
int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
- boolean visible; // does this activity's window need to be shown?
+ private boolean mVisible; // Should this token's windows be visible?
boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
// might hide this activity?
- // True if the hidden state of this token was forced to false due to a transferred starting
+ // True if the visible state of this token was forced to true due to a transferred starting
// window.
- private boolean mHiddenSetFromTransferredStartingWindow;
- // TODO: figureout how to consolidate with the same variable in ActivityRecord.
+ private boolean mVisibleSetFromTransferredStartingWindow;
+ // TODO: figure out how to consolidate with the same variable in ActivityRecord.
private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
// process that it is hidden.
- private boolean mLastDeferHidingClient; // If true we will defer setting mClientHidden to true
+ private boolean mLastDeferHidingClient; // If true we will defer setting mClientVisible to false
// and reporting to the client that it is hidden.
boolean sleeping; // have we told the activity to sleep?
boolean nowVisible; // is this activity's window visible?
@@ -537,8 +536,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private Task mLastParent;
- // Have we told the window clients to hide themselves?
- private boolean mClientHidden;
+ // Have we told the window clients to show themselves?
+ private boolean mClientVisible;
boolean firstWindowDrawn;
// Last drawn state we reported to the app token.
@@ -623,11 +622,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// case do not clear allDrawn until the animation completes.
boolean deferClearAllDrawn;
- // Is this window's surface needed? This is almost like hidden, except
- // it will sometimes be true a little earlier: when the token has
+ // Is this window's surface needed? This is almost like visible, except
+ // it will sometimes be true a little earlier: when the activity record has
// been shown, but is still waiting for its app transition to execute
// before making its windows shown.
- boolean hiddenRequested;
+ boolean mVisibleRequested;
// Last visibility state we reported to the app token.
boolean reportedVisible;
@@ -837,7 +836,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
- pw.print(" visible="); pw.print(visible);
pw.print(" sleeping="); pw.print(sleeping);
pw.print(" idle="); pw.print(idle);
pw.print(" mStartingWindowState=");
@@ -856,12 +854,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.println(requestedVrComponent);
}
super.dump(pw, prefix, dumpAll);
+ pw.print(" visible="); pw.print(mVisible);
if (appToken != null) {
pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
}
pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent);
pw.print(" mOrientation="); pw.println(mOrientation);
- pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
+ pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
+ + " mClientVisible=" + mClientVisible
+ ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
+ " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
if (paused) {
@@ -886,13 +886,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" mIsExiting="); pw.println(mIsExiting);
}
if (startingWindow != null || startingSurface != null
- || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
+ || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
pw.print(" startingSurface="); pw.print(startingSurface);
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
pw.print(" startingMoved="); pw.print(startingMoved);
pw.println(" mHiddenSetFromTransferredStartingWindow="
- + mHiddenSetFromTransferredStartingWindow);
+ + mVisibleSetFromTransferredStartingWindow);
}
if (!mFrozenBounds.isEmpty()) {
pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
@@ -1148,7 +1148,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- TaskRecord getTaskRecord() {
+ Task getTask() {
return task;
}
@@ -1156,33 +1156,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Sets the Task on this activity for the purposes of re-use during launch where we will
* re-use another activity instead of this one for the launch.
*/
- void setTaskForReuse(TaskRecord task) {
+ void setTaskForReuse(Task task) {
this.task = task;
}
- Task getTask() {
- return (Task) getParent();
- }
-
TaskStack getStack() {
- final Task task = getTask();
- if (task != null) {
- return task.getTaskStack();
- } else {
- return null;
- }
+ return task != null ? task.getTaskStack() : null;
}
@Override
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null;
- final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null;
+ final Task oldTask = oldParent != null ? (Task) oldParent : null;
+ final Task newTask = newParent != null ? (Task) newParent : null;
this.task = newTask;
super.onParentChanged(newParent, oldParent);
- final Task task = getTask();
-
if (oldParent == null && newParent != null) {
// First time we are adding the activity to the system.
mVoiceInteraction = newTask.voiceSession != null;
@@ -1311,7 +1300,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// represents this. In fullscreen-mode, the stack does (since the orientation letterbox
// is also applied to the task).
Rect spaceToFill = (inMultiWindowMode() || getStack() == null)
- ? getTask().getDisplayedBounds() : getStack().getDisplayedBounds();
+ ? task.getDisplayedBounds() : getStack().getDisplayedBounds();
mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
} else if (mLetterbox != null) {
mLetterbox.hide();
@@ -1499,8 +1488,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Application tokens start out hidden.
- setHidden(true);
- hiddenRequested = true;
+ setVisible(false);
+ mVisibleRequested = false;
ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
ColorDisplayService.ColorDisplayServiceInternal.class);
@@ -1529,9 +1518,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
deferRelaunchUntilPaused = false;
keysPaused = false;
inHistory = false;
- visible = false;
nowVisible = false;
mDrawn = false;
+ mClientVisible = true;
idle = false;
hasBeenLaunched = false;
mStackSupervisor = supervisor;
@@ -1637,8 +1626,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
final ActivityManager.TaskSnapshot snapshot =
- mWmService.mTaskSnapshotController.getSnapshot(
- getTask().mTaskId, getTask().mUserId,
+ mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* reducedResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, fromRecents, snapshot);
@@ -1823,7 +1811,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (snapshot == null) {
return false;
}
- return getTask().getConfiguration().orientation == snapshot.getOrientation();
+ return task.getConfiguration().orientation == snapshot.getOrientation();
}
void removeStartingWindow() {
@@ -1893,12 +1881,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Reparents this activity into {@param newTask} at the provided {@param position}. The caller
* should ensure that the {@param newTask} is not already the parent of this activity.
*/
- void reparent(TaskRecord newTask, int position, String reason) {
+ void reparent(Task newTask, int position, String reason) {
if (getParent() == null) {
Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken);
return;
}
- final TaskRecord prevTask = task;
+ final Task prevTask = task;
if (prevTask == newTask) {
throw new IllegalArgumentException(reason + ": task=" + newTask
+ " is already the parent of r=" + this);
@@ -1985,7 +1973,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
setActivityType(activityType);
}
- void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
+ void setTaskToAffiliateWith(Task taskToAffiliateWith) {
if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
task.setTaskToAffiliateWith(taskToAffiliateWith);
}
@@ -2213,7 +2201,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* 2. App is delayed closing since it might enter PIP.
*/
boolean isClosingOrEnteringPip() {
- return (isAnimating(TRANSITION | PARENTS) && hiddenRequested) || mWillCloseOrEnterPip;
+ return (isAnimating(TRANSITION | PARENTS) && !mVisibleRequested) || mWillCloseOrEnterPip;
}
/**
* @return Whether AppOps allows this package to enter picture-in-picture.
@@ -2241,7 +2229,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
}
- return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable();
+ return (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable())
+ && getParent() != null;
}
/** Move activity with its stack to front and make the stack focused. */
@@ -2253,7 +2242,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
- final TaskRecord task = getTaskRecord();
final ActivityStack stack = getActivityStack();
if (stack == null) {
Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
@@ -2282,7 +2270,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Finish all activities in the task with the same affinity as this one. */
void finishActivityAffinity() {
- final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren;
+ final ArrayList<ActivityRecord> activities = task.mChildren;
for (int index = activities.indexOf(this); index >= 0; --index) {
final ActivityRecord cur = activities.get(index);
if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
@@ -2390,7 +2378,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAtmService.deferWindowLayout();
try {
makeFinishingLocked();
- final TaskRecord task = getTaskRecord();
+ // Make a local reference to its task since this.task could be set to null once this
+ // activity is destroyed and detached from task.
+ final Task task = getTask();
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
mUserId, System.identityHashCode(this),
task.mTaskId, shortComponentName, reason);
@@ -2470,7 +2460,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAtmService.getLockTaskController().clearLockedTask(task);
}
} else if (!isState(PAUSING)) {
- if (visible) {
+ if (mVisibleRequested) {
// Prepare and execute close transition.
prepareActivityHideTransitionAnimation(transit);
}
@@ -2549,12 +2539,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
final ActivityRecord next = getDisplay().topRunningActivity(
true /* considerKeyguardState */);
- final boolean isVisible = visible || nowVisible;
+ final boolean isVisible = mVisibleRequested || nowVisible;
// isNextNotYetVisible is to check if the next activity is invisible, or it has been
// requested to be invisible but its windows haven't reported as invisible. If so, it
// implied that the current finishing activity should be added into stopping list rather
// than destroy immediately.
- final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible);
+ final boolean isNextNotYetVisible = next != null
+ && (!next.nowVisible || !next.mVisibleRequested);
if (isVisible && isNextNotYetVisible) {
// Add this activity to the list of stopping activities. It will be processed and
// destroyed when the next activity reports idle.
@@ -2667,16 +2658,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
- System.identityHashCode(this), getTaskRecord().mTaskId, shortComponentName, reason);
+ System.identityHashCode(this), task.mTaskId, shortComponentName, reason);
+
+ final ActivityStack stack = getActivityStack();
+ if (hasProcess() && !stack.inLruList(this)) {
+ Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
+ }
boolean removedFromHistory = false;
cleanUp(false /* cleanServices */, false /* setState */);
- final ActivityStack stack = getActivityStack();
- final boolean hadApp = hasProcess();
-
- if (hadApp) {
+ if (hasProcess()) {
if (removeFromApp) {
app.removeActivity(this);
if (!app.hasActivities()) {
@@ -2741,10 +2734,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
configChangeFlags = 0;
- if (!stack.removeActivityFromLRUList(this) && hadApp) {
- Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
- }
-
return removedFromHistory;
}
@@ -2870,8 +2859,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
boolean shouldFreezeBounds() {
- final Task task = getTask();
-
// For freeform windows, we can't freeze the bounds at the moment because this would make
// the resizing unresponsive.
if (task == null || task.inFreeformWindowingMode()) {
@@ -2882,7 +2869,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// the divider/drag handle being released, and the handling it's new
// configuration. If we are relaunched outside of the drag resizing state,
// we need to be careful not to do this.
- return getTask().isDragResizing();
+ return task.isDragResizing();
}
void startRelaunching() {
@@ -2906,7 +2893,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* with a queue.
*/
private void freezeBounds() {
- final Task task = getTask();
mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
@@ -3227,7 +3213,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"Removing starting %s from %s", tStartingWindow, fromActivity);
fromActivity.removeChild(tStartingWindow);
fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
- fromActivity.mHiddenSetFromTransferredStartingWindow = false;
+ fromActivity.mVisibleSetFromTransferredStartingWindow = false;
addWindow(tStartingWindow);
// Propagate other interesting state between the tokens. If the old token is displayed,
@@ -3240,12 +3226,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (fromActivity.firstWindowDrawn) {
firstWindowDrawn = true;
}
- if (!fromActivity.isHidden()) {
- setHidden(false);
- hiddenRequested = false;
- mHiddenSetFromTransferredStartingWindow = true;
+ if (fromActivity.isVisible()) {
+ setVisible(true);
+ mVisibleRequested = true;
+ mVisibleSetFromTransferredStartingWindow = true;
}
- setClientHidden(fromActivity.mClientHidden);
+ setClientVisible(fromActivity.mClientVisible);
transferAnimation(fromActivity);
@@ -3286,13 +3272,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* immediately finishes after, so we have to transfer T to M.
*/
void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
- final Task task = getTask();
for (int i = task.mChildren.size() - 1; i >= 0; i--) {
final ActivityRecord fromActivity = task.mChildren.get(i);
if (fromActivity == this) {
return;
}
- if (fromActivity.hiddenRequested && transferStartingWindow(fromActivity.token)) {
+ if (!fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token)) {
return;
}
}
@@ -3398,7 +3383,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
@Nullable
private ActivityRecord getActivityBelow() {
- final Task task = getTask();
final int pos = task.mChildren.indexOf(this);
if (pos == -1) {
throw new IllegalStateException("Activity not found in its task");
@@ -3474,7 +3458,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void logStartActivity(int tag, TaskRecord task) {
+ void logStartActivity(int tag, Task task) {
final Uri data = intent.getData();
final String strData = data != null ? data.toSafeString() : null;
@@ -3808,6 +3792,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return opts;
}
+ boolean allowMoveToFront() {
+ return pendingOptions == null || !pendingOptions.getAvoidMoveToFront();
+ }
+
void removeUriPermissionsLocked() {
if (uriPermissions != null) {
uriPermissions.removeUriPermissions();
@@ -3844,7 +3832,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
mDeferHidingClient = deferHidingClient;
- if (!mDeferHidingClient && !visible) {
+ if (!mDeferHidingClient && !mVisibleRequested) {
// Hiding the client is no longer deferred and the app isn't visible still, go ahead and
// update the visibility.
setVisibility(false);
@@ -3855,7 +3843,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean isVisible() {
// If the activity isn't hidden then it is considered visible and there is no need to check
// its children windows to see if they are visible.
- return !isHidden();
+ return mVisible;
+ }
+
+ void setVisible(boolean visible) {
+ if (visible != mVisible) {
+ mVisible = visible;
+ scheduleAnimation();
+ }
}
void setVisibility(boolean visible) {
@@ -3864,20 +3859,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
+ appToken);
return;
}
+ if (visible) {
+ mDeferHidingClient = false;
+ }
setVisibility(visible, mDeferHidingClient);
mAtmService.addWindowLayoutReasons(
ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
- }
-
- // TODO: Look into merging with #commitVisibility()
- void setVisible(boolean newVisible) {
- visible = newVisible;
- mDeferHidingClient = !visible && mDeferHidingClient;
- setVisibility(visible);
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
+ @VisibleForTesting
void setVisibility(boolean visible, boolean deferHidingClient) {
final AppTransition appTransition = getDisplayContent().mAppTransition;
@@ -3888,20 +3880,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// transition can be selected.
// TODO: Probably a good idea to separate the concept of opening/closing apps from the
// concept of setting visibility...
- if (!visible && hiddenRequested) {
+ if (!visible && !mVisibleRequested) {
if (!deferHidingClient && mLastDeferHidingClient) {
// We previously deferred telling the client to hide itself when visibility was
// initially set to false. Now we would like it to hide, so go ahead and set it.
mLastDeferHidingClient = deferHidingClient;
- setClientHidden(true);
+ setClientVisible(false);
}
return;
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
- appToken, visible, appTransition, isHidden(), hiddenRequested,
+ "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+ appToken, visible, appTransition, isVisible(), mVisibleRequested,
Debug.getCallers(6));
final DisplayContent displayContent = getDisplayContent();
@@ -3912,7 +3904,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
displayContent.mChangingApps.remove(this);
waitingToShow = false;
- hiddenRequested = !visible;
+ mVisibleRequested = visible;
mLastDeferHidingClient = deferHidingClient;
if (!visible) {
@@ -3931,15 +3923,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
startingMoved = false;
// If the token is currently hidden (should be the common case), or has been
// stopped, then we need to set up to wait for its windows to be ready.
- if (isHidden() || mAppStopped) {
+ if (!isVisible() || mAppStopped) {
clearAllDrawn();
// If the app was already visible, don't reset the waitingToShow state.
- if (isHidden()) {
+ if (!isVisible()) {
waitingToShow = true;
// If the client isn't hidden, we don't need to reset the drawing state.
- if (isClientHidden()) {
+ if (!isClientVisible()) {
// Let's reset the draw state in order to prevent the starting window to be
// immediately dismissed when the app still has the surface.
forAllWindows(w -> {
@@ -3959,7 +3951,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// we still need to tell the client to make its windows visible so they get drawn.
// Otherwise, we will wait on performing the transition until all windows have been
// drawn, they never will be, and we are sad.
- setClientHidden(false);
+ setClientVisible(true);
requestUpdateWallpaperIfNeeded();
@@ -4005,9 +3997,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
boolean delayed = false;
- // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
+ // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
// been set by the app now.
- mHiddenSetFromTransferredStartingWindow = false;
+ mVisibleSetFromTransferredStartingWindow = false;
// Allow for state changes and animation to be applied if:
// * token is transitioning visibility state
@@ -4017,7 +4009,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// * or the token is the opening app and visible while opening task behind existing one.
final DisplayContent displayContent = getDisplayContent();
boolean visibilityChanged = false;
- if (isHidden() == visible || (isHidden() && mIsExiting)
+ if (isVisible() != visible || (!isVisible() && mIsExiting)
|| (visible && waitingForReplacement())
|| (visible && displayContent.mOpeningApps.contains(this)
&& displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) {
@@ -4025,7 +4017,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mWmService.mAccessibilityController;
boolean changed = false;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Changing app %s hidden=%b performLayout=%b", this, isHidden(),
+ "Changing app %s visible=%b performLayout=%b", this, isVisible(),
performLayout);
boolean runningAppAnimation = false;
@@ -4050,8 +4042,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
}
- setHidden(!visible);
- hiddenRequested = !visible;
+ setVisible(visible);
+ mVisibleRequested = visible;
visibilityChanged = true;
if (!visible) {
stopFreezingScreen(true, true);
@@ -4069,8 +4061,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "commitVisibility: %s: hidden=%b hiddenRequested=%b", this,
- isHidden(), hiddenRequested);
+ "commitVisibility: %s: visible=%b visibleRequested=%b", this,
+ isVisible(), mVisibleRequested);
if (changed) {
displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
@@ -4107,7 +4099,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// If we're becoming invisible, update the client visibility if we are not running an
// animation. Otherwise, we'll update client visibility in onAnimationFinished.
if (visible || !isAnimating()) {
- setClientHidden(!visible);
+ setClientVisible(visible);
}
if (!displayContent.mClosingApps.contains(this)
@@ -4134,7 +4126,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// no animation but there will still be a transition set.
// We still need to delay hiding the surface such that it
// can be synchronized with showing the next surface in the transition.
- if (isHidden() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
+ if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
SurfaceControl.openTransaction();
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).mWinAnimator.hide("immediately hidden");
@@ -4147,12 +4139,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
- void setHidden(boolean hidden) {
- super.setHidden(hidden);
- scheduleAnimation();
- }
-
- @Override
void onAppTransitionDone() {
sendingToBottom = false;
}
@@ -4211,10 +4197,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mState = state;
- final TaskRecord parent = getTaskRecord();
-
- if (parent != null) {
- parent.onActivityStateChanged(this, state, reason);
+ if (task != null) {
+ task.onActivityStateChanged(this, state, reason);
}
// The WindowManager interprets the app stopping signal as
@@ -4417,7 +4401,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
updateOptionsLocked(returningOptions);
stack.mUndrawnActivitiesBelowTopTranslucent.add(this);
}
- setVisible(true);
+ setVisibility(true);
sleeping = false;
app.postPendingUiCleanMsg(true);
if (reportToClient) {
@@ -4453,7 +4437,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void makeInvisible() {
- if (!visible) {
+ if (!mVisibleRequested) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
return;
}
@@ -4475,7 +4459,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STOPPING, STOPPED, PAUSED);
setDeferHidingClient(deferHidingClient);
- setVisible(false);
+ setVisibility(false);
switch (getState()) {
case STOPPING:
@@ -4662,8 +4646,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* state to match that fact.
*/
void completeResumeLocked() {
- final boolean wasVisible = visible;
- setVisible(true);
+ final boolean wasVisible = mVisibleRequested;
+ setVisibility(true);
if (!wasVisible) {
// Visibility has changed, so take a note of it so we call the TaskStackChangedListener
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
@@ -4747,15 +4731,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
setState(STOPPING, "stopIfPossible");
if (DEBUG_VISIBILITY) {
- Slog.v(TAG_VISIBILITY, "Stopping visible=" + visible + " for " + this);
+ Slog.v(TAG_VISIBILITY, "Stopping visibleRequested="
+ + mVisibleRequested + " for " + this);
}
- if (!visible) {
- setVisible(false);
+ if (!mVisibleRequested) {
+ setVisibility(false);
}
EventLogTags.writeAmStopActivity(
mUserId, System.identityHashCode(this), shortComponentName);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- StopActivityItem.obtain(visible, configChangeFlags));
+ StopActivityItem.obtain(mVisibleRequested, configChangeFlags));
if (stack.shouldSleepOrShutDownActivities()) {
setSleeping(true);
}
@@ -4918,10 +4903,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void startFreezingScreen() {
ProtoLog.i(WM_DEBUG_ORIENTATION,
- "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
- appToken, isHidden(), mFreezingScreen, hiddenRequested,
+ "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+ appToken, isVisible(), mFreezingScreen, mVisibleRequested,
new RuntimeException().fillInStackTrace());
- if (!hiddenRequested) {
+ if (mVisibleRequested) {
if (!mFreezingScreen) {
mFreezingScreen = true;
mWmService.registerAppFreezeListener(this);
@@ -4957,8 +4942,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
ProtoLog.v(WM_DEBUG_ORIENTATION,
- "Clear freezing of %s: hidden=%b freezing=%b", appToken,
- isHidden(), isFreezingScreen());
+ "Clear freezing of %s: visible=%b freezing=%b", appToken,
+ isVisible(), isFreezingScreen());
stopFreezingScreen(true, force);
}
}
@@ -5118,7 +5103,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean nowGone = mReportedVisibilityResults.nowGone;
boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
- boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden();
+ boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible();
if (!nowGone) {
// If the app is not yet gone, then it can only become visible/drawn.
if (!nowDrawn) {
@@ -5146,18 +5131,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- boolean isClientHidden() {
- return mClientHidden;
+ boolean isClientVisible() {
+ return mClientVisible;
}
- void setClientHidden(boolean hideClient) {
- if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
+ void setClientVisible(boolean clientVisible) {
+ if (mClientVisible == clientVisible || (!clientVisible && mDeferHidingClient)) {
return;
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "setClientHidden: %s clientHidden=%b Callers=%s", this, hideClient,
+ "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible,
Debug.getCallers(5));
- mClientHidden = hideClient;
+ mClientVisible = clientVisible;
sendAppVisibilityToClients();
}
@@ -5200,7 +5185,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
+ " pv=" + w.isVisibleByPolicy()
+ " mDrawState=" + winAnimator.drawStateToString()
- + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
+ + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested
+ " a=" + isAnimating(TRANSITION));
}
}
@@ -5308,7 +5293,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* currently pausing, or is resumed.
*/
public boolean isInterestingToUserLocked() {
- return visible || nowVisible || mState == PAUSING || mState == RESUMED;
+ return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
}
void setSleeping(boolean _sleeping) {
@@ -5337,7 +5322,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (r == null) {
return INVALID_TASK_ID;
}
- final TaskRecord task = r.task;
+ final Task task = r.task;
final int activityNdx = task.mChildren.indexOf(r);
if (activityNdx < 0
|| (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
@@ -5382,7 +5367,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// We're not ready for this kind of thing.
return false;
}
- if (visible) {
+ if (mVisibleRequested) {
// The user would notice this!
return false;
}
@@ -5479,11 +5464,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// well there is no point now.
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData");
mStartingData = null;
- if (mHiddenSetFromTransferredStartingWindow) {
- // We set the hidden state to false for the token from a transferred starting window.
- // We now reset it back to true since the starting window was the last window in the
- // token.
- setHidden(true);
+ if (mVisibleSetFromTransferredStartingWindow) {
+ // We set the visible state to true for the token from a transferred starting
+ // window. We now reset it back to false since the starting window was the last
+ // window in the token.
+ setVisible(false);
}
} else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
// If this is the last window except for a starting transition window,
@@ -5631,7 +5616,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting
boolean shouldAnimate(int transit) {
- final Task task = getTask();
if (task != null && !task.shouldAnimate()) {
return false;
}
@@ -5647,11 +5631,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
boolean isChangingAppTransition() {
- final Task task = getTask();
- if (task != null) {
- return task.isChangingAppTransition();
- }
- return super.isChangingAppTransition();
+ return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition();
}
@Override
@@ -5751,7 +5731,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- Task task = getTask();
if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) {
SurfaceControl.ScreenshotGraphicBuffer snapshot =
mWmService.mTaskSnapshotController.createTaskSnapshot(
@@ -5803,7 +5782,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// of the pinned stack or animation layer. The leash is then reparented to this new layer.
if (mNeedsAnimationBoundsLayer) {
mTmpRect.setEmpty();
- final Task task = getTask();
if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
getTransit(), task)) {
task.getBounds(mTmpRect);
@@ -5828,7 +5806,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
void prepareSurfaces() {
- final boolean show = !isHidden() || isAnimating();
+ final boolean show = isVisible() || isAnimating();
if (mSurfaceControl != null) {
if (show && !mLastSurfaceShowing) {
@@ -5860,9 +5838,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
final GraphicBuffer thumbnailHeader =
- getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(getTask());
+ getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task);
if (thumbnailHeader == null) {
- ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", getTask());
+ ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task);
return;
}
clearThumbnail();
@@ -5886,7 +5864,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
final Rect frame = win.getFrameLw();
- final int thumbnailDrawableRes = getTask().mUserId == mWmService.mCurrentUserId
+ final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
? R.drawable.ic_account_circle
: R.drawable.ic_corp_badge;
final GraphicBuffer thumbnail =
@@ -5916,7 +5894,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Rect insets = win != null ? win.getContentInsets() : null;
final Configuration displayConfig = mDisplayContent.getConfiguration();
return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
- appRect, insets, thumbnailHeader, getTask(), displayConfig.uiMode,
+ appRect, insets, thumbnailHeader, task, displayConfig.uiMode,
displayConfig.orientation);
}
@@ -5947,7 +5925,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"AppWindowToken");
clearThumbnail();
- setClientHidden(isHidden() && hiddenRequested);
+ setClientVisible(isVisible() || mVisibleRequested);
getDisplayContent().computeImeTargetIfNeeded(this);
@@ -6256,7 +6234,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Ensure the screen related fields are set. It is used to prevent activity relaunch
// when moving between displays. For screenWidthDp and screenWidthDp, because they
// are relative to bounds and density, they will be calculated in
- // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
+ // {@link Task#computeConfigResourceOverrides} and the result will also be
// relatively fixed.
overrideConfig.colorMode = fullConfig.colorMode;
overrideConfig.densityDpi = fullConfig.densityDpi;
@@ -6366,9 +6344,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (rotation != ROTATION_UNDEFINED) {
// Ensure the parent and container bounds won't overlap with insets.
- TaskRecord.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
+ Task.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
mCompatDisplayInsets.mNonDecorInsets[rotation]);
- TaskRecord.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
+ Task.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
mCompatDisplayInsets.mNonDecorInsets[rotation]);
}
@@ -6415,7 +6393,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
Rect getDisplayedBounds() {
- final Task task = getTask();
if (task != null) {
final Rect overrideDisplayedBounds = task.getOverrideDisplayedBounds();
if (!overrideDisplayedBounds.isEmpty()) {
@@ -6434,7 +6411,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Use task-bounds if available so that activity-level letterbox (maxAspectRatio) is
// included in the animation.
- return getTask() != null ? getTask().getBounds() : getBounds();
+ return task != null ? task.getBounds() : getBounds();
}
/**
@@ -6504,7 +6481,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTmpPrevBounds.set(getBounds());
super.onConfigurationChanged(newParentConfig);
- final Task task = getTask();
final Rect overrideBounds = getResolvedOverrideBounds();
if (task != null && !overrideBounds.isEmpty()
// If the changes come from change-listener, the incoming parent configuration is
@@ -6546,7 +6522,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (display == null) {
return;
}
- if (visible) {
+ if (mVisibleRequested) {
// It may toggle the UI for user to restart the size compatibility mode activity.
display.handleActivitySizeCompatModeIfNeeded(this);
} else if (mCompatDisplayInsets != null) {
@@ -6680,7 +6656,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Compute configuration based on max supported width and height.
// Also account for the left / top insets (e.g. from display cutouts), which will be clipped
- // away later in {@link TaskRecord#computeConfigResourceOverrides()}. Otherwise, the app
+ // away later in {@link Task#computeConfigResourceOverrides()}. Otherwise, the app
// bounds would end up too small.
outBounds.set(containingBounds.left, containingBounds.top,
activityWidth + containingAppBounds.left,
@@ -6822,7 +6798,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
preserveWindow &= isResizeOnlyChange(changes);
final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
if (hasResizeChange) {
- final boolean isDragResizing = getTaskRecord().isDragResizing();
+ final boolean isDragResizing = task.isDragResizing();
mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
: RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
} else {
@@ -6843,7 +6819,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching " + this);
- if (DEBUG_STATES && !visible) {
+ if (DEBUG_STATES && !mVisibleRequested) {
Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
+ " called by " + Debug.getCallers(4));
}
@@ -7029,7 +7005,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Reset the existing override configuration so it can be updated according to the latest
// configuration.
clearSizeCompatMode();
- if (visible) {
+ if (mVisibleRequested) {
// Configuration will be ensured when becoming visible, so if it is already visible,
// then the manual update is needed.
updateSizeCompatMode();
@@ -7042,7 +7018,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// The restarting state avoids removing this record when process is died.
setState(RESTARTING_PROCESS, "restartActivityProcess");
- if (!visible || mHaveState) {
+ if (!mVisibleRequested || mHaveState) {
// Kill its process immediately because the activity should be in background.
// The activity state will be update to {@link #DESTROYED} in
// {@link ActivityStack#cleanUp} when handling process died.
@@ -7333,12 +7309,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
writeToProto(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL);
writeIdentifierToProto(proto, IDENTIFIER);
proto.write(STATE, mState.toString());
- proto.write(VISIBLE, visible);
+ proto.write(VISIBLE_REQUESTED, mVisibleRequested);
proto.write(FRONT_OF_TASK, isRootOfTask());
if (hasProcess()) {
proto.write(PROC_ID, app.getPid());
}
proto.write(TRANSLUCENT, !occludesParent());
+ proto.write(VISIBLE, mVisible);
}
public void writeToProto(ProtoOutputStream proto, long fieldId) {
@@ -7369,8 +7346,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
proto.write(FILLS_PARENT, mOccludesParent);
proto.write(APP_STOPPED, mAppStopped);
- proto.write(HIDDEN_REQUESTED, hiddenRequested);
- proto.write(CLIENT_HIDDEN, mClientHidden);
+ proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE_REQUESTED, mVisibleRequested);
+ proto.write(CLIENT_VISIBLE, mClientVisible);
proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
proto.write(REPORTED_DRAWN, reportedDrawn);
proto.write(REPORTED_VISIBLE, reportedVisible);
@@ -7384,11 +7361,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
proto.write(STARTING_DISPLAYED, startingDisplayed);
proto.write(STARTING_MOVED, startingMoved);
- proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW,
- mHiddenSetFromTransferredStartingWindow);
+ proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
+ mVisibleSetFromTransferredStartingWindow);
for (Rect bounds : mFrozenBounds) {
bounds.writeToProto(proto, FROZEN_BOUNDS);
}
+ proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE, mVisible);
proto.end(token);
}
@@ -7429,7 +7407,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Rect[] mStableInsets = new Rect[4];
/**
- * Sets bounds to {@link TaskRecord} bounds. For apps in freeform, the task bounds are the
+ * Sets bounds to {@link Task} bounds. For apps in freeform, the task bounds are the
* parent bounds from the app's perspective. No insets because within a window.
*/
CompatDisplayInsets(DisplayContent display, Rect activityBounds, boolean isFloating) {
@@ -7489,7 +7467,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
RemoteAnimationTarget createRemoteAnimationTarget(
RemoteAnimationController.RemoteAnimationRecord record) {
- final Task task = getTask();
final WindowState mainWindow = findMainWindow();
if (task == null || mainWindow == null) {
return null;
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index c56a9e2ac560..6e75f9c9167f 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -73,7 +73,7 @@ public class ActivityServiceConnectionsHolder<T> {
public boolean isActivityVisible() {
synchronized (mService.mGlobalLock) {
- return mActivity.visible || mActivity.isState(RESUMED, PAUSING);
+ return mActivity.mVisibleRequested || mActivity.isState(RESUMED, PAUSING);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ef7e4dc4c8a5..2aea81724627 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -98,7 +98,7 @@ import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.RootActivityContainer.FindTaskResult;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -297,7 +297,7 @@ class ActivityStack extends TaskStack {
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
*/
- private final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
+ private final ArrayList<ActivityRecord> mLruActivities = new ArrayList<>();
/**
* When we are in the process of pausing an activity, before starting the
@@ -494,7 +494,7 @@ class ActivityStack extends TaskStack {
/**
* This should be called when an activity in a child task changes state. This should only
* be called from
- * {@link TaskRecord#onActivityStateChanged(ActivityRecord, ActivityState, String)}.
+ * {@link Task#onActivityStateChanged(ActivityRecord, ActivityState, String)}.
* @param record The {@link ActivityRecord} whose state has changed.
* @param state The new state.
* @param reason The reason for the change.
@@ -511,7 +511,7 @@ class ActivityStack extends TaskStack {
if (record == mRootActivityContainer.getTopResumedActivity()) {
mService.setResumedActivityUncheckLocked(record, reason);
}
- mStackSupervisor.mRecentTasks.add(record.getTaskRecord());
+ mStackSupervisor.mRecentTasks.add(record.getTask());
}
}
@@ -584,7 +584,7 @@ class ActivityStack extends TaskStack {
final boolean isMinimizedDock =
display.mDisplayContent.getDockedDividerController().isMinimizedDock();
if (isMinimizedDock) {
- TaskRecord topTask = display.getSplitScreenPrimaryStack().topTask();
+ Task topTask = display.getSplitScreenPrimaryStack().topTask();
if (topTask != null) {
dockedBounds = topTask.getBounds();
}
@@ -661,7 +661,7 @@ class ActivityStack extends TaskStack {
final int currentMode = getWindowingMode();
final int currentOverrideMode = getRequestedOverrideWindowingMode();
final ActivityDisplay display = getDisplay();
- final TaskRecord topTask = topTask();
+ final Task topTask = topTask();
final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
int windowingMode = preferredWindowingMode;
if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
@@ -835,11 +835,11 @@ class ActivityStack extends TaskStack {
return mRootActivityContainer.getActivityDisplay(mDisplayId);
}
- void positionChildAtTop(TaskRecord child) {
+ void positionChildAtTop(Task child) {
positionChildAtTop(child, true /* includingParents */);
}
- private void positionChildAtBottom(TaskRecord child) {
+ private void positionChildAtBottom(Task child) {
// If there are other focusable stacks on the display, the z-order of the display should not
// be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
// task to bottom, the next focusable stack on the same display should be focused.
@@ -927,7 +927,7 @@ class ActivityStack extends TaskStack {
ActivityRecord topRunningNonOverlayTaskActivity() {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (!r.finishing && !r.mTaskOverlay) {
@@ -940,7 +940,7 @@ class ActivityStack extends TaskStack {
ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
@@ -962,7 +962,7 @@ class ActivityStack extends TaskStack {
*/
final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- TaskRecord task = getChildAt(taskNdx);
+ Task task = getChildAt(taskNdx);
if (task.mTaskId == taskId) {
continue;
}
@@ -987,7 +987,7 @@ class ActivityStack extends TaskStack {
return null;
}
- final TaskRecord topTask() {
+ final Task topTask() {
final int size = getChildCount();
if (size > 0) {
return getChildAt(size - 1);
@@ -995,9 +995,9 @@ class ActivityStack extends TaskStack {
return null;
}
- TaskRecord taskForIdLocked(int id) {
+ Task taskForIdLocked(int id) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
if (task.mTaskId == id) {
return task;
}
@@ -1014,7 +1014,7 @@ class ActivityStack extends TaskStack {
if (r == null) {
return null;
}
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
final ActivityStack stack = r.getActivityStack();
if (stack != null && task.mChildren.contains(r) && mChildren.contains(task)) {
if (stack != this) Slog.w(TAG,
@@ -1024,14 +1024,14 @@ class ActivityStack extends TaskStack {
return null;
}
- boolean isInStackLocked(TaskRecord task) {
+ boolean isInStackLocked(Task task) {
return mChildren.contains(task);
}
/** Checks if there are tasks with specific UID in the stack. */
boolean isUidPresent(int uid) {
for (int j = getChildCount() - 1; j >= 0; --j) {
- final TaskRecord task = getChildAt(j);
+ final Task task = getChildAt(j);
for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
final ActivityRecord r = task.getChildAt(i);
if (r.getUid() == uid) {
@@ -1045,7 +1045,7 @@ class ActivityStack extends TaskStack {
/** Get all UIDs that are present in the stack. */
void getPresentUIDs(IntArray presentUIDs) {
for (int j = getChildCount() - 1; j >= 0; --j) {
- final TaskRecord task = getChildAt(j);
+ final Task task = getChildAt(j);
for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
final ActivityRecord r = task.getChildAt(i);
presentUIDs.add(r.getUid());
@@ -1060,14 +1060,15 @@ class ActivityStack extends TaskStack {
}
/** @return {@code true} if LRU list contained the specified activity. */
- final boolean removeActivityFromLRUList(ActivityRecord activity) {
- return mLRUActivities.remove(activity);
+ final boolean inLruList(ActivityRecord activity) {
+ return mLruActivities.contains(activity);
}
- final boolean updateLRUListLocked(ActivityRecord r) {
- final boolean hadit = mLRUActivities.remove(r);
- mLRUActivities.add(r);
- return hadit;
+ /** @return {@code true} if the given activity was contained in LRU list. */
+ final boolean updateLruList(ActivityRecord r) {
+ final boolean contained = mLruActivities.remove(r);
+ mLruActivities.add(r);
+ return contained;
}
final boolean isHomeOrRecentsStack() {
@@ -1092,7 +1093,7 @@ class ActivityStack extends TaskStack {
* @param reason The reason for moving the stack to the front.
* @param task If non-null, the task will be moved to the top of the stack.
* */
- void moveToFront(String reason, TaskRecord task) {
+ void moveToFront(String reason, Task task) {
if (!isAttached()) {
return;
}
@@ -1134,7 +1135,7 @@ class ActivityStack extends TaskStack {
* @param reason The reason for moving the stack to the back.
* @param task If non-null, the task will be moved to the bottom of the stack.
**/
- void moveToBack(String reason, TaskRecord task) {
+ void moveToBack(String reason, Task task) {
if (!isAttached()) {
return;
}
@@ -1186,7 +1187,7 @@ class ActivityStack extends TaskStack {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
@@ -1227,7 +1228,7 @@ class ActivityStack extends TaskStack {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
- + "/aff=" + r.getTaskRecord().rootAffinity + " to new cls="
+ + "/aff=" + r.getTask().rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
@@ -1277,7 +1278,7 @@ class ActivityStack extends TaskStack {
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (!r.okToShowLocked()) {
@@ -1311,7 +1312,7 @@ class ActivityStack extends TaskStack {
super.switchUser(userId);
int top = mChildren.size();
for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
- TaskRecord task = mChildren.get(taskNdx);
+ Task task = mChildren.get(taskNdx);
if (mWmService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
mChildren.remove(taskNdx);
mChildren.add(task);
@@ -1338,7 +1339,7 @@ class ActivityStack extends TaskStack {
void awakeFromSleepingLocked() {
// Ensure activities are no longer sleeping.
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
r.setSleeping(false);
@@ -1355,7 +1356,7 @@ class ActivityStack extends TaskStack {
final int userId = UserHandle.getUserId(aInfo.uid);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord ar = task.getChildAt(activityNdx);
@@ -1433,7 +1434,7 @@ class ActivityStack extends TaskStack {
// Make sure any paused or stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
@@ -1499,7 +1500,7 @@ class ActivityStack extends TaskStack {
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.setState(PAUSING, "startPausingLocked");
- prev.getTaskRecord().touchActiveTime();
+ prev.getTask().touchActiveTime();
clearLaunchTime(prev);
mService.updateCpuStats();
@@ -1628,7 +1629,8 @@ class ActivityStack extends TaskStack {
prev = prev.completeFinishing("completePausedLocked");
} else if (prev.hasProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
- + " wasStopping=" + wasStopping + " visible=" + prev.visible);
+ + " wasStopping=" + wasStopping
+ + " visibleRequested=" + prev.mVisibleRequested);
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
@@ -1638,7 +1640,7 @@ class ActivityStack extends TaskStack {
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.setState(STOPPING, "completePausedLocked");
- } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
+ } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
@@ -1717,7 +1719,7 @@ class ActivityStack extends TaskStack {
return true;
}
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
@@ -1759,7 +1761,7 @@ class ActivityStack extends TaskStack {
boolean isTopActivityVisible() {
final ActivityRecord topActivity = getTopActivity();
- return topActivity != null && topActivity.visible;
+ return topActivity != null && topActivity.mVisibleRequested;
}
/**
@@ -1898,9 +1900,9 @@ class ActivityStack extends TaskStack {
final int rankTaskLayers(int baseLayer) {
int layer = 0;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
ActivityRecord r = task.topRunningActivityLocked();
- if (r == null || r.finishing || !r.visible) {
+ if (r == null || r.finishing || !r.mVisibleRequested) {
task.mLayerRank = -1;
} else {
task.mLayerRank = baseLayer + layer++;
@@ -1949,7 +1951,7 @@ class ActivityStack extends TaskStack {
final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null
&& top != null && !top.mLaunchTaskBehind;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
final boolean isTop = r == top;
@@ -1989,7 +1991,7 @@ class ActivityStack extends TaskStack {
if (!r.attachedToProcess()) {
makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
resumeTopActivity && isTop, r);
- } else if (r.visible) {
+ } else if (r.mVisibleRequested) {
// If this activity is already visible, then there is nothing to do here.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Skipping: already visible at " + r);
@@ -2068,7 +2070,7 @@ class ActivityStack extends TaskStack {
@Override
public boolean supportsSplitScreenWindowingMode() {
- final TaskRecord topTask = topTask();
+ final Task topTask = topTask();
return super.supportsSplitScreenWindowingMode()
&& (topTask == null || topTask.supportsSplitScreenWindowingMode());
}
@@ -2166,16 +2168,16 @@ class ActivityStack extends TaskStack {
// invisible. If the app is already visible, it must have died while it was visible. In this
// case, we'll show the dead window but will not restart the app. Otherwise we could end up
// thrashing.
- if (isTop || !r.visible) {
+ if (isTop || !r.mVisibleRequested) {
// This activity needs to be visible, but isn't even running...
// get it started and resume if no other stack in this stack is resumed.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
if (r != starting) {
r.startFreezingScreenLocked(configChanges);
}
- if (!r.visible || r.mLaunchTaskBehind) {
+ if (!r.mVisibleRequested || r.mLaunchTaskBehind) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
- r.setVisible(true);
+ r.setVisibility(true);
}
if (r != starting) {
mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
@@ -2193,7 +2195,7 @@ class ActivityStack extends TaskStack {
void clearOtherAppTimeTrackers(AppTimeTracker except) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if ( r.appTimeTracker != except) {
@@ -2267,7 +2269,7 @@ class ActivityStack extends TaskStack {
final ActivityRecord topActivity = topRunningActivityLocked();
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (aboveTop) {
@@ -2581,7 +2583,7 @@ class ActivityStack extends TaskStack {
dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
dc.prepareAppTransition(
- prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_CLOSE
+ prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
prev.setVisibility(false);
@@ -2593,7 +2595,7 @@ class ActivityStack extends TaskStack {
dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
dc.prepareAppTransition(
- prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_OPEN
+ prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
}
@@ -2618,7 +2620,8 @@ class ActivityStack extends TaskStack {
if (next.attachedToProcess()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
- + " stopped=" + next.stopped + " visible=" + next.visible);
+ + " stopped=" + next.stopped
+ + " visibleRequested=" + next.mVisibleRequested);
// If the previous activity is translucent, force a visibility update of
// the next activity, so that it's added to WM's opening app list, and
@@ -2633,7 +2636,7 @@ class ActivityStack extends TaskStack {
&& !lastFocusedStack.mLastPausedActivity.occludesParent()));
// This activity is now becoming visible.
- if (!next.visible || next.stopped || lastActivityTranslucent) {
+ if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
next.setVisibility(true);
}
@@ -2653,7 +2656,7 @@ class ActivityStack extends TaskStack {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, true /* updateOomAdj */);
- updateLRUListLocked(next);
+ updateLruList(next);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
@@ -2688,7 +2691,7 @@ class ActivityStack extends TaskStack {
// Do over!
mStackSupervisor.scheduleResumeTopActivities();
}
- if (!next.visible || next.stopped) {
+ if (!next.mVisibleRequested || next.stopped) {
next.setVisibility(true);
}
next.completeResumeLocked();
@@ -2719,7 +2722,7 @@ class ActivityStack extends TaskStack {
next.notifyAppResumed(next.stopped);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.mUserId,
- System.identityHashCode(next), next.getTaskRecord().mTaskId,
+ System.identityHashCode(next), next.getTask().mTaskId,
next.shortComponentName);
next.sleeping = false;
@@ -2817,7 +2820,7 @@ class ActivityStack extends TaskStack {
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
- TaskRecord rTask = r.getTaskRecord();
+ Task rTask = r.getTask();
final int taskId = rTask.mTaskId;
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
// mLaunchTaskBehind tasks get placed at the back of the task stack.
@@ -2828,7 +2831,7 @@ class ActivityStack extends TaskStack {
// Might not even be in.
positionChildAtTop(rTask);
}
- TaskRecord task = null;
+ Task task = null;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
@@ -2860,7 +2863,7 @@ class ActivityStack extends TaskStack {
// If we are not placing the new activity frontmost, we do not want to deliver the
// onUserLeaving callback to the actual frontmost activity
- final TaskRecord activityTask = r.getTaskRecord();
+ final Task activityTask = r.getTask();
if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
@@ -2933,12 +2936,12 @@ class ActivityStack extends TaskStack {
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
- TaskRecord prevTask = r.getTaskRecord();
+ Task prevTask = r.getTask();
ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
- if (prev.getTaskRecord() != prevTask) {
+ if (prev.getTask() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
@@ -2961,7 +2964,7 @@ class ActivityStack extends TaskStack {
* {@param toFrontActivity} should be set.
*/
private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate,
- TaskRecord toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
+ Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) {
// Ensure the caller has requested not to trigger auto-enter PiP
return false;
@@ -2981,7 +2984,7 @@ class ActivityStack extends TaskStack {
private boolean isTaskSwitch(ActivityRecord r,
ActivityRecord topFocusedActivity) {
- return topFocusedActivity != null && r.getTaskRecord() != topFocusedActivity.getTaskRecord();
+ return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
}
/**
@@ -2991,7 +2994,7 @@ class ActivityStack extends TaskStack {
* @param forceReset Flag indicating if clear task was requested
* @return An ActivityOptions that needs to be processed.
*/
- private ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
+ private ActivityOptions resetTargetTaskIfNeededLocked(Task task, boolean forceReset) {
ActivityOptions topOptions = null;
// Tracker of the end of currently handled reply chain (sublist) of activities. What happens
@@ -3045,19 +3048,19 @@ class ActivityStack extends TaskStack {
// moved.
// TODO: We should probably look for other stacks also, since corresponding task
// with the same affinity is unlikely to be in the same stack.
- final TaskRecord targetTask;
+ final Task targetTask;
final ActivityRecord bottom =
hasChild() && getChildAt(0).hasChild() ?
getChildAt(0).getChildAt(0) : null;
- if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
+ if (bottom != null && target.taskAffinity.equals(bottom.getTask().affinity)) {
// If the activity currently at the bottom has the
// same task affinity as the one we are moving,
// then merge it into the same task.
- targetTask = bottom.getTaskRecord();
+ targetTask = bottom.getTask();
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
+ " out to bottom task " + targetTask);
} else {
- targetTask = createTaskRecord(
+ targetTask = createTask(
mStackSupervisor.getNextTaskIdForUserLocked(target.mUserId),
target.info, null /* intent */, null /* voiceSession */,
null /* voiceInteractor */, false /* toTop */);
@@ -3150,7 +3153,7 @@ class ActivityStack extends TaskStack {
if (singleTaskInstanceDisplay || display.alwaysCreateStack(getWindowingMode(),
getActivityType())) {
for (int index = numTasksCreated - 1; index >= 0; index--) {
- final TaskRecord targetTask = getChildAt(index);
+ final Task targetTask = getChildAt(index);
final ActivityStack targetStack = display.getOrCreateStack(getWindowingMode(),
getActivityType(), false /* onTop */);
targetTask.reparent(targetStack, false /* toTop */,
@@ -3165,7 +3168,7 @@ class ActivityStack extends TaskStack {
/**
* Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}.
- * Processes all of the activities in a given TaskRecord looking for an affinity with the task
+ * Processes all of the activities in a given Task looking for an affinity with the task
* of resetTaskIfNeededLocked.taskTop.
* @param affinityTask The task we are looking for an affinity to.
* @param task Task that resetTaskIfNeededLocked.taskTop belongs to.
@@ -3173,7 +3176,7 @@ class ActivityStack extends TaskStack {
* @param forceReset Flag indicating if clear task was requested
*/
// TODO: Consider merging with #resetTargetTaskIfNeededLocked() above
- private int resetAffinityTaskIfNeededLocked(TaskRecord affinityTask, TaskRecord task,
+ private int resetAffinityTaskIfNeededLocked(Task affinityTask, Task task,
boolean topTaskIsHigher, boolean forceReset, int taskInsertionPoint) {
// Tracker of the end of currently handled reply chain (sublist) of activities. What happens
// to activities in the same chain will depend on what the end activity of the chain needs.
@@ -3289,9 +3292,9 @@ class ActivityStack extends TaskStack {
ActivityRecord newActivity) {
final boolean forceReset =
(newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
- final TaskRecord task = taskTop.getTaskRecord();
+ final Task task = taskTop.getTask();
- // False until we evaluate the TaskRecord associated with taskTop. Switches to true
+ // False until we evaluate the Task associated with taskTop. Switches to true
// for remaining tasks. Used for later tasks to reparent to task.
boolean taskFound = false;
@@ -3302,7 +3305,7 @@ class ActivityStack extends TaskStack {
int reparentInsertionPoint = -1;
for (int i = getChildCount() - 1; i >= 0; --i) {
- final TaskRecord targetTask = getChildAt(i);
+ final Task targetTask = getChildAt(i);
if (targetTask == task) {
topOptions = resetTargetTaskIfNeededLocked(task, forceReset);
@@ -3357,7 +3360,7 @@ class ActivityStack extends TaskStack {
final ActivityRecord top = stack.topRunningActivityLocked();
- if (stack.isActivityTypeHome() && (top == null || !top.visible)) {
+ if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
// If we will be focusing on the home stack next and its current top activity isn't
// visible, then use the move the home stack task to top to make the activity visible.
stack.getDisplay().moveHomeActivityToTop(reason);
@@ -3379,7 +3382,7 @@ class ActivityStack extends TaskStack {
/** Finish all activities that were started for result from the specified activity. */
final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (r.resultTo == self && r.requestCode == requestCode) {
@@ -3401,17 +3404,17 @@ class ActivityStack extends TaskStack {
* @return The task that was finished in this stack, {@code null} if top running activity does
* not belong to the crashed app.
*/
- final TaskRecord finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
+ final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
ActivityRecord r = topRunningActivityLocked();
- TaskRecord finishedTask = null;
+ Task finishedTask = null;
if (r == null || r.app != app) {
return null;
}
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- finishedTask = r.getTaskRecord();
+ finishedTask = r.getTask();
int taskNdx = mChildren.indexOf(finishedTask);
- final TaskRecord task = finishedTask;
+ final Task task = finishedTask;
int activityNdx = task.mChildren.indexOf(r);
getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
@@ -3447,7 +3450,7 @@ class ActivityStack extends TaskStack {
IBinder sessionBinder = session.asBinder();
boolean didOne = false;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- TaskRecord tr = getChildAt(taskNdx);
+ Task tr = getChildAt(taskNdx);
if (tr.voiceSession != null && tr.voiceSession.asBinder() == sessionBinder) {
for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = tr.getChildAt(activityNdx);
@@ -3485,7 +3488,7 @@ class ActivityStack extends TaskStack {
void finishAllActivitiesImmediately() {
boolean noActivitiesInStack = true;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
noActivitiesInStack = false;
@@ -3515,15 +3518,15 @@ class ActivityStack extends TaskStack {
boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- if (srec == null || srec.getTaskRecord().affinity == null ||
- !srec.getTaskRecord().affinity.equals(destAffinity)) {
+ if (srec == null || srec.getTask().affinity == null
+ || !srec.getTask().affinity.equals(destAffinity)) {
return true;
}
// Document-centric case: an app may be split in to multiple documents;
// they need to re-create their task if this current activity is the root
// of a document, unless simply finishing it will return them to the the
// correct app behind.
- final TaskRecord task = srec.getTaskRecord();
+ final Task task = srec.getTask();
if (srec.isRootOfTask() && task.getBaseIntent() != null
&& task.getBaseIntent().isDocument()) {
// Okay, this activity is at the root of its task. What to do, what to do...
@@ -3537,7 +3540,7 @@ class ActivityStack extends TaskStack {
Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
return false;
}
- final TaskRecord prevTask = getChildAt(taskIdx);
+ final Task prevTask = getChildAt(taskIdx);
if (!task.affinity.equals(prevTask.affinity)) {
// These are different apps, so need to recreate.
return true;
@@ -3548,7 +3551,7 @@ class ActivityStack extends TaskStack {
final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
Intent resultData) {
- final TaskRecord task = srec.getTaskRecord();
+ final Task task = srec.getTask();
final ArrayList<ActivityRecord> activities = task.mChildren;
final int start = activities.indexOf(srec);
if (!mChildren.contains(task) || (start < 0)) {
@@ -3643,10 +3646,10 @@ class ActivityStack extends TaskStack {
* an activity moves away from the stack.
*/
void onActivityRemovedFromStack(ActivityRecord r) {
- removeActivityFromLRUList(r);
removeTimeoutsForActivity(r);
mExitingActivities.remove(r);
+ mLruActivities.remove(r);
if (mResumedActivity != null && mResumedActivity == r) {
setResumedActivity(null, "onActivityRemovedFromStack");
@@ -3657,9 +3660,12 @@ class ActivityStack extends TaskStack {
}
void onActivityAddedToStack(ActivityRecord r) {
- if(r.getState() == RESUMED) {
+ if (r.isState(RESUMED)) {
setResumedActivity(r, "onActivityAddedToStack");
}
+ if (r.hasProcess()) {
+ updateLruList(r);
+ }
}
/// HANDLER INTERFACE BEGIN
@@ -3724,7 +3730,7 @@ class ActivityStack extends TaskStack {
boolean lastIsOpaque = false;
boolean activityRemoved = false;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (r.finishing) {
@@ -3755,7 +3761,7 @@ class ActivityStack extends TaskStack {
}
}
- final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<TaskRecord> tasks,
+ final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<Task> tasks,
String reason) {
// Iterate over tasks starting at the back (oldest) first.
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
@@ -3765,7 +3771,7 @@ class ActivityStack extends TaskStack {
}
int numReleased = 0;
for (int taskNdx = 0; taskNdx < getChildCount() && maxTasks > 0; taskNdx++) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
if (!tasks.contains(task)) {
continue;
}
@@ -3817,7 +3823,7 @@ class ActivityStack extends TaskStack {
}
private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
- removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
+ removeHistoryRecordsForAppLocked(mLruActivities, app, "mLruActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
@@ -3851,7 +3857,7 @@ class ActivityStack extends TaskStack {
"Record #" + targetIndex + " " + r + ": app=" + r.app);
if (r.app == app) {
- if (r.visible) {
+ if (r.mVisibleRequested) {
hasVisibleActivities = true;
}
final boolean remove;
@@ -3867,8 +3873,8 @@ class ActivityStack extends TaskStack {
// Don't currently have state for the activity, or
// it is finishing -- always remove it.
remove = true;
- } else if (!r.visible && r.launchCount > 2 &&
- r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+ } else if (!r.mVisibleRequested && r.launchCount > 2
+ && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
// We have launched this activity too many times since it was
// able to run, so give up and remove it.
// (Note if the activity is visible, we don't remove the record.
@@ -3890,7 +3896,7 @@ class ActivityStack extends TaskStack {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.mUserId, System.identityHashCode(r),
- r.getTaskRecord().mTaskId, r.shortComponentName,
+ r.getTask().mTaskId, r.shortComponentName,
"proc died without state saved");
}
} else {
@@ -3904,7 +3910,7 @@ class ActivityStack extends TaskStack {
// it died, we leave the dead window on screen so it's basically visible.
// This is needed when user later tap on the dead window, we need to stop
// other apps when user transfers focus to the restarted activity.
- r.nowVisible = r.visible;
+ r.nowVisible = r.mVisibleRequested;
}
r.cleanUp(true /* cleanServices */, true /* setState */);
if (remove) {
@@ -3929,7 +3935,7 @@ class ActivityStack extends TaskStack {
getDisplay().mDisplayContent.prepareAppTransition(transit, false);
}
- final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
+ final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
AppTimeTracker timeTracker, String reason) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
@@ -3968,7 +3974,7 @@ class ActivityStack extends TaskStack {
final ActivityRecord top = tr.getTopActivity();
if (top == null || !top.okToShowLocked()) {
if (top != null) {
- mStackSupervisor.mRecentTasks.add(top.getTaskRecord());
+ mStackSupervisor.mRecentTasks.add(top.getTask());
}
ActivityOptions.abort(options);
return;
@@ -4021,7 +4027,7 @@ class ActivityStack extends TaskStack {
* @return Returns true if the move completed, false if not.
*/
final boolean moveTaskToBackLocked(int taskId) {
- final TaskRecord tr = taskForIdLocked(taskId);
+ final Task tr = taskForIdLocked(taskId);
if (tr == null) {
Slog.i(TAG, "moveTaskToBack: bad taskId=" + taskId);
return false;
@@ -4086,18 +4092,18 @@ class ActivityStack extends TaskStack {
* Ensures all visible activities at or below the input activity have the right configuration.
*/
void ensureVisibleActivitiesConfigurationLocked(ActivityRecord start, boolean preserveWindow) {
- if (start == null || !start.visible) {
+ if (start == null || !start.mVisibleRequested) {
return;
}
- final TaskRecord startTask = start.getTaskRecord();
+ final Task startTask = start.getTask();
boolean behindFullscreen = false;
boolean updatedConfig = false;
for (int taskIndex = mChildren.indexOf(startTask); taskIndex >= 0; --taskIndex) {
- final TaskRecord task = getChildAt(taskIndex);
+ final Task task = getChildAt(taskIndex);
final ArrayList<ActivityRecord> activities = task.mChildren;
- int activityIndex = (start.getTaskRecord() == task)
+ int activityIndex = (start.getTask() == task)
? activities.indexOf(start) : activities.size() - 1;
for (; activityIndex >= 0; --activityIndex) {
final ActivityRecord r = activities.get(activityIndex);
@@ -4133,7 +4139,7 @@ class ActivityStack extends TaskStack {
// Update override configurations of all tasks in the stack.
final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
for (int i = getChildCount() - 1; i >= 0; i--) {
- final TaskRecord task = getChildAt(i);
+ final Task task = getChildAt(i);
if (task.isResizeable()) {
if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) {
task.setOverrideDisplayedBounds(taskBounds);
@@ -4167,7 +4173,7 @@ class ActivityStack extends TaskStack {
}
for (int i = getChildCount() - 1; i >= 0; i--) {
- final TaskRecord task = getChildAt(i);
+ final Task task = getChildAt(i);
if (task.isResizeable()) {
task.setBounds(bounds);
} else {
@@ -4183,7 +4189,7 @@ class ActivityStack extends TaskStack {
}
for (int i = getChildCount() - 1; i >= 0; i--) {
- final TaskRecord task = getChildAt(i);
+ final Task task = getChildAt(i);
if (bounds == null || bounds.isEmpty()) {
task.setOverrideDisplayedBounds(null);
} else if (task.isResizeable()) {
@@ -4194,7 +4200,7 @@ class ActivityStack extends TaskStack {
boolean willActivityBeVisibleLocked(IBinder token) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (r.appToken == token) {
@@ -4216,7 +4222,7 @@ class ActivityStack extends TaskStack {
void closeSystemDialogsLocked() {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
@@ -4229,7 +4235,7 @@ class ActivityStack extends TaskStack {
boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
boolean doit, boolean evenPersistent, int userId) {
boolean didSomething = false;
- TaskRecord lastTask = null;
+ Task lastTask = null;
ComponentName homeActivity = null;
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
@@ -4243,7 +4249,7 @@ class ActivityStack extends TaskStack {
|| filterByClasses.contains(r.mActivityComponent.getClassName())))
|| (packageName == null && r.mUserId == userId);
if ((userId == UserHandle.USER_ALL || r.mUserId == userId)
- && (sameComponent || r.getTaskRecord() == lastTask)
+ && (sameComponent || r.getTask() == lastTask)
&& (r.app == null || evenPersistent || !r.app.isPersistent())) {
if (!doit) {
if (r.finishing) {
@@ -4263,7 +4269,7 @@ class ActivityStack extends TaskStack {
}
didSomething = true;
Slog.i(TAG, " Force finishing activity " + r);
- lastTask = r.getTaskRecord();
+ lastTask = r.getTask();
r.finishIfPossible("force-stop", true);
}
}
@@ -4276,14 +4282,14 @@ class ActivityStack extends TaskStack {
* If {@param ignoreActivityType} or {@param ignoreWindowingMode} are not undefined,
* then skip running tasks that match those types.
*/
- void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType,
+ void getRunningTasks(List<Task> tasksOut, @ActivityType int ignoreActivityType,
@WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed,
boolean crossUser, ArraySet<Integer> profileIds) {
boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this;
boolean topTask = true;
int userId = UserHandle.getUserId(callingUid);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
if (task.getTopActivity() == null) {
// Skip if there are no activities in the task
continue;
@@ -4325,7 +4331,7 @@ class ActivityStack extends TaskStack {
final int top = getChildCount() - 1;
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
if (top >= 0) {
- final TaskRecord task = getChildAt(top);
+ final Task task = getChildAt(top);
int activityTop = task.getChildCount() - 1;
if (activityTop >= 0) {
task.getChildAt(activityTop).finishIfPossible("unhandled-back", true /* oomAdj */);
@@ -4354,7 +4360,7 @@ class ActivityStack extends TaskStack {
void handleAppCrash(WindowProcessController app) {
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = task.getChildAt(activityNdx);
if (r.app == app) {
@@ -4381,7 +4387,7 @@ class ActivityStack extends TaskStack {
boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
needSep);
- printed |= dumpHistoryList(fd, pw, mLRUActivities, " ", "Run", false,
+ printed |= dumpHistoryList(fd, pw, mLruActivities, " ", "Run", false,
!dumpAll, false, dumpPackage, true,
" Running activities (most recent first):", null);
@@ -4419,7 +4425,7 @@ class ActivityStack extends TaskStack {
}
final String prefix = " ";
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
if (needSep) {
pw.println("");
}
@@ -4446,7 +4452,7 @@ class ActivityStack extends TaskStack {
} else if ("top".equals(name)) {
final int top = getChildCount() - 1;
if (top >= 0) {
- final TaskRecord task = getChildAt(top);
+ final Task task = getChildAt(top);
int listTop = task.getChildCount() - 1;
if (listTop >= 0) {
activities.add(task.getChildAt(listTop));
@@ -4457,7 +4463,7 @@ class ActivityStack extends TaskStack {
matcher.build(name);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r1 = task.getChildAt(activityNdx);
if (matcher.match(r1, r1.intent.getComponent())) {
@@ -4476,12 +4482,12 @@ class ActivityStack extends TaskStack {
// All activities that came from the package must be
// restarted as if there was a config change.
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord a = task.getChildAt(activityNdx);
if (a.info.packageName.equals(packageName)) {
a.forceNewConfig = true;
- if (starting != null && a == starting && a.visible) {
+ if (starting != null && a == starting && a.mVisibleRequested) {
a.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
}
}
@@ -4497,7 +4503,7 @@ class ActivityStack extends TaskStack {
* @param child to remove.
* @param reason for removal.
*/
- void removeChild(TaskRecord child, String reason) {
+ void removeChild(Task child, String reason) {
if (!mChildren.contains(child)) {
// Not really in this stack anymore...
return;
@@ -4526,7 +4532,7 @@ class ActivityStack extends TaskStack {
}
@Override
- void removeChild(TaskRecord task) {
+ void removeChild(Task task) {
removeChild(task, "removeChild");
}
@@ -4542,18 +4548,18 @@ class ActivityStack extends TaskStack {
}
}
- TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ Task createTask(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop) {
- return createTaskRecord(taskId, info, intent, voiceSession, voiceInteractor, toTop,
+ return createTask(taskId, info, intent, voiceSession, voiceInteractor, toTop,
null /*activity*/, null /*source*/, null /*options*/);
}
- TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ Task createTask(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop, ActivityRecord activity, ActivityRecord source,
ActivityOptions options) {
- final TaskRecord task = TaskRecord.create(
+ final Task task = Task.create(
mService, taskId, info, intent, voiceSession, voiceInteractor, this);
// add the task to stack first, mTaskPositioner might need the stack association
addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
@@ -4568,11 +4574,11 @@ class ActivityStack extends TaskStack {
return task;
}
- ArrayList<TaskRecord> getAllTasks() {
+ ArrayList<Task> getAllTasks() {
return new ArrayList<>(mChildren);
}
- void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) {
+ void addChild(final Task task, final boolean toTop, boolean showForAllUsers) {
if (isSingleTaskInstance() && hasChild()) {
throw new IllegalStateException("Can only have one child on stack=" + this);
}
@@ -4587,8 +4593,7 @@ class ActivityStack extends TaskStack {
}
}
- void positionChildAt(TaskRecord task, int position) {
-
+ void positionChildAt(Task task, int position) {
if (task.getStack() != this) {
throw new IllegalArgumentException("AS.positionChildAt: task=" + task
+ " is not a child of stack=" + this + " current parent=" + task.getStack());
@@ -4646,7 +4651,7 @@ class ActivityStack extends TaskStack {
display.positionChildAtTop(this, false /* includingParents */);
}
- /** NOTE: Should only be called from {@link TaskRecord#reparent}. */
+ /** NOTE: Should only be called from {@link Task#reparent}. */
void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
boolean setPause, String reason) {
if (!moveToFront) {
@@ -4659,7 +4664,7 @@ class ActivityStack extends TaskStack {
// Apps may depend on onResume()/onPause() being called in pairs.
if (setResume) {
r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded");
- updateLRUListLocked(r);
+ updateLruList(r);
}
// If the activity was previously pausing, then ensure we transfer that as well
if (setPause) {
@@ -4707,8 +4712,14 @@ class ActivityStack extends TaskStack {
throw new RuntimeException("There should be only one task in a pinned stack.");
}
+ // give pinned stack a chance to save current bounds, this should happen before reparent.
+ final ActivityRecord top = topRunningNonOverlayTaskActivity();
+ if (top != null && top.isVisible()) {
+ top.savePinnedStackBounds();
+ }
+
mWindowManager.inSurfaceTransaction(() -> {
- final TaskRecord task = mChildren.get(0);
+ final Task task = mChildren.get(0);
setWindowingMode(WINDOWING_MODE_UNDEFINED);
getDisplay().positionChildAtTop(this, false /* includingParents */);
@@ -4727,7 +4738,7 @@ class ActivityStack extends TaskStack {
if (!isAttached()) {
return;
}
- ArrayList<TaskRecord> tasks = getAllTasks();
+ ArrayList<Task> tasks = getAllTasks();
for (int i = 0; i < tasks.size(); i++) {
mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
forceUpdate);
@@ -4783,7 +4794,7 @@ class ActivityStack extends TaskStack {
writeToProtoInnerStackOnly(proto, STACK, logLevel);
proto.write(ID, mStackId);
for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = getChildAt(taskNdx);
+ final Task task = getChildAt(taskNdx);
task.writeToProto(proto, TASKS, logLevel);
}
if (mResumedActivity != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e34006665864..4828a8d864e9 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -75,12 +75,12 @@ import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_O
import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.RootActivityContainer.TAG_STATES;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -740,7 +740,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
return false;
}
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
final ActivityStack stack = task.getStack();
beginDeferResume();
@@ -773,12 +773,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
if (r.getActivityStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
- true /* isTop */)) {
- // We only set the visibility to true if the activity is allowed to be visible
- // based on
- // keyguard state. This avoids setting this into motion in window manager that is
- // later cancelled due to later calls to ensure visible activities that set
- // visibility back to false.
+ true /* isTop */) && r.allowMoveToFront()) {
+ // We only set the visibility to true if the activity is not being launched in
+ // background, and is allowed to be visible based on keyguard state. This avoids
+ // setting this into motion in window manager that is later cancelled due to later
+ // calls to ensure visible activities that set visibility back to false.
r.setVisibility(true);
}
@@ -913,7 +912,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
r.launchFailed = false;
- if (stack.updateLRUListLocked(r)) {
+ if (stack.updateLruList(r)) {
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
@@ -1382,7 +1381,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
/** This doesn't just find a task, it also moves the task to front. */
- void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason,
+ void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason,
boolean forceNonResizeable) {
ActivityStack currentStack = task.getStack();
if (currentStack == null) {
@@ -1480,7 +1479,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
continueUpdateRecentsHomeStackBounds();
for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
final int taskId = mResizingTasksDuringAnimation.valueAt(i);
- final TaskRecord task =
+ final Task task =
mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY);
if (task != null) {
task.setTaskDockedResizing(false);
@@ -1527,13 +1526,13 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// the picture-in-picture mode.
final boolean schedulePictureInPictureModeChange =
windowingMode == WINDOWING_MODE_PINNED;
- final ArrayList<TaskRecord> tasks = fromStack.getAllTasks();
+ final ArrayList<Task> tasks = fromStack.getAllTasks();
if (!tasks.isEmpty()) {
mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
final int size = tasks.size();
for (int i = 0; i < size; ++i) {
- final TaskRecord task = tasks.get(i);
+ final Task task = tasks.get(i);
final ActivityStack toStack = toDisplay.getOrCreateStack(
null, mTmpOptions, task, task.getActivityType(), onTop);
@@ -1745,7 +1744,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
private void removeStackInSurfaceTransaction(ActivityStack stack) {
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final ArrayList<Task> tasks = stack.getAllTasks();
if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
/**
* Workaround: Force-stop all the activities in the pinned stack before we reparent them
@@ -1791,14 +1790,14 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
*/
boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
String reason) {
- final TaskRecord tr =
+ final Task task =
mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
- if (tr != null) {
- tr.removeTaskActivitiesLocked(reason);
- cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
- mService.getLockTaskController().clearLockedTask(tr);
+ if (task != null) {
+ task.removeTaskActivitiesLocked(reason);
+ cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
+ mService.getLockTaskController().clearLockedTask(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
- if (tr.isPersistable) {
+ if (task.isPersistable) {
mService.notifyTaskPersisterLocked(null, true);
}
return true;
@@ -1807,19 +1806,19 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
return false;
}
- void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) {
+ void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
- mRecentTasks.remove(tr);
+ mRecentTasks.remove(task);
}
- ComponentName component = tr.getBaseIntent().getComponent();
+ ComponentName component = task.getBaseIntent().getComponent();
if (component == null) {
- Slog.w(TAG, "No component for base intent of task: " + tr);
+ Slog.w(TAG, "No component for base intent of task: " + task);
return;
}
// Find any running services associated with this app and stop if needed.
final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
- mService.mAmInternal, tr.mUserId, component, new Intent(tr.getBaseIntent()));
+ mService.mAmInternal, task.mUserId, component, new Intent(task.getBaseIntent()));
mService.mH.sendMessage(msg);
if (!killProcess) {
@@ -1836,7 +1835,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
SparseArray<WindowProcessController> uids = pmap.valueAt(i);
for (int j = 0; j < uids.size(); j++) {
WindowProcessController proc = uids.valueAt(j);
- if (proc.mUserId != tr.mUserId) {
+ if (proc.mUserId != task.mUserId) {
// Don't kill process for a different user.
continue;
}
@@ -1849,7 +1848,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
continue;
}
- if (!proc.shouldKillProcessForRemovedTask(tr)) {
+ if (!proc.shouldKillProcessForRemovedTask(task)) {
// Don't kill process(es) that has an activity in a different task that is also
// in recents, or has an activity not stopped.
return;
@@ -1881,7 +1880,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
* @param onTop If the stack for the task should be the topmost on the display.
* @return true if the task has been restored successfully.
*/
- boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions, boolean onTop) {
+ boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) {
final ActivityStack stack =
mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop);
final ActivityStack currentStack = task.getStack();
@@ -1904,12 +1903,12 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
@Override
- public void onRecentTaskAdded(TaskRecord task) {
+ public void onRecentTaskAdded(Task task) {
task.touchActiveTime();
}
@Override
- public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+ public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
if (wasTrimmed) {
// Task was trimmed from the recent tasks list -- remove the active task record as well
// since the user won't really be able to go back to it
@@ -1924,7 +1923,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
* the various checks on tasks that are going to be reparented from one stack to another.
*/
// TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
- ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
+ ActivityStack getReparentTargetStack(Task task, ActivityStack stack, boolean toTop) {
final ActivityStack prevStack = task.getStack();
final int stackId = stack.mStackId;
final boolean inMultiWindowMode = stack.inMultiWindowMode();
@@ -2077,7 +2076,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Called when WindowManager has finished animating the launchingBehind activity to the back.
private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
final ActivityStack stack = task.getStack();
mRecentTasks.add(task);
@@ -2088,7 +2087,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// task has been shown briefly
final ActivityRecord top = stack.getTopActivity();
if (top != null) {
- top.getTaskRecord().touchActiveTime();
+ top.getTask().touchActiveTime();
}
}
@@ -2207,7 +2206,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
String prefix, String label, boolean complete, boolean brief, boolean client,
- String dumpPackage, boolean needNL, String header, TaskRecord lastTask) {
+ String dumpPackage, boolean needNL, String header, Task lastTask) {
String innerPrefix = null;
String[] args = null;
boolean printed = false;
@@ -2230,8 +2229,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
pw.println(header);
header = null;
}
- if (lastTask != r.getTaskRecord()) {
- lastTask = r.getTaskRecord();
+ if (lastTask != r.getTask()) {
+ lastTask = r.getTask();
pw.print(prefix);
pw.print(full ? "* " : " ");
pw.println(lastTask);
@@ -2391,13 +2390,13 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION);
}
- void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
+ void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode,
int preferredDisplayId, ActivityStack actualStack) {
handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
actualStack, false /* forceNonResizable */);
}
- void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
+ void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode,
int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) {
final boolean isSecondaryDisplayPreferred =
(preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
@@ -2466,7 +2465,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
/** Notifies that the top activity of the task is forced to be resizeable. */
- private void handleForcedResizableTaskIfNeeded(TaskRecord task, int reason) {
+ private void handleForcedResizableTaskIfNeeded(Task task, int reason) {
final ActivityRecord topActivity = task.getTopActivity();
if (topActivity == null || topActivity.noDisplay
|| !topActivity.isNonResizableOrForcedResizable(task.getWindowingMode())) {
@@ -2490,7 +2489,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mActivityMetricsLogger.logWindowState();
}
- void scheduleUpdateMultiWindowMode(TaskRecord task) {
+ void scheduleUpdateMultiWindowMode(Task task) {
// If the stack is animating in a way where we will be forcing a multi-mode change at the
// end, then ensure that we defer all in between multi-window mode changes
if (task.getStack().deferScheduleMultiWindowModeChanged()) {
@@ -2509,7 +2508,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
- void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, ActivityStack prevStack) {
+ void scheduleUpdatePictureInPictureModeIfNeeded(Task task, ActivityStack prevStack) {
final ActivityStack stack = task.getStack();
if (prevStack == null || prevStack == stack
|| (!prevStack.inPinnedWindowingMode() && !stack.inPinnedWindowingMode())) {
@@ -2519,7 +2518,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getRequestedOverrideBounds());
}
- void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
+ void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
for (int i = task.getChildCount() - 1; i >= 0; i--) {
final ActivityRecord r = task.getChildAt(i);
if (r.attachedToProcess()) {
@@ -2537,7 +2536,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
- void updatePictureInPictureMode(TaskRecord task, Rect targetStackBounds, boolean forceUpdate) {
+ void updatePictureInPictureMode(Task task, Rect targetStackBounds, boolean forceUpdate) {
mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
for (int i = task.getChildCount() - 1; i >= 0; i--) {
final ActivityRecord r = task.getChildAt(i);
@@ -2694,14 +2693,14 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
*
* @param task The task to put into resizing mode
*/
- void setResizingDuringAnimation(TaskRecord task) {
+ void setResizingDuringAnimation(Task task) {
mResizingTasksDuringAnimation.add(task.mTaskId);
task.setTaskDockedResizing(true);
}
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
- TaskRecord task = null;
+ Task task = null;
final String callingPackage;
final Intent intent;
final int userId;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index e2e2b743d011..d3fd450f311a 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -182,9 +182,17 @@ public class ActivityStartController {
final ActivityDisplay display =
mService.mRootActivityContainer.getActivityDisplay(displayId);
- // Make sure home stack exist on display.
- final ActivityStack homeStack =
- display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ // The home activity will be started later, defer resuming to avoid unneccerary operations
+ // (e.g. start home recursively) when creating home stack.
+ mSupervisor.beginDeferResume();
+ final ActivityStack homeStack;
+ try {
+ // Make sure home stack exist on display.
+ homeStack = display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
+ ON_TOP);
+ } finally {
+ mSupervisor.endDeferResume();
+ }
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
@@ -271,7 +279,7 @@ public class ActivityStartController {
final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ int userId, Task inTask, String reason, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index effd154a6aa0..8420695bbdd6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -97,7 +97,7 @@ class ActivityStartInterceptor {
ResolveInfo mRInfo;
ActivityInfo mAInfo;
String mResolvedType;
- TaskRecord mInTask;
+ Task mInTask;
ActivityOptions mActivityOptions;
ActivityStartInterceptor(
@@ -144,7 +144,7 @@ class ActivityStartInterceptor {
* @return true if an interception occurred
*/
boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
- TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
+ Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
mUserManager = UserManager.get(mServiceContext);
mIntent = intent;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5cb1df260b89..2218c7237e76 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -82,7 +82,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -175,9 +175,9 @@ class ActivityStarter {
// The display to launch the activity onto, barring any strong reason to do otherwise.
private int mPreferredDisplayId;
- private TaskRecord mInTask;
+ private Task mInTask;
private boolean mAddingToTask;
- private TaskRecord mReuseTask;
+ private Task mReuseTask;
private ActivityInfo mNewTaskInfo;
private Intent mNewTaskIntent;
@@ -330,7 +330,7 @@ class ActivityStarter {
boolean componentSpecified;
boolean avoidMoveToFront;
ActivityRecord[] outActivity;
- TaskRecord inTask;
+ Task inTask;
String reason;
ProfilerInfo profilerInfo;
Configuration globalConfig;
@@ -571,7 +571,7 @@ class ActivityStarter {
*/
void startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+ int startFlags, boolean doResume, ActivityOptions options, Task inTask) {
try {
mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
mLastStartReason = "startResolvedActivity";
@@ -808,7 +808,7 @@ class ActivityStarter {
final int realCallingUid = request.realCallingUid;
final int startFlags = request.startFlags;
final SafeActivityOptions options = request.activityOptions;
- TaskRecord inTask = request.inTask;
+ Task inTask = request.inTask;
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
@@ -895,7 +895,7 @@ class ActivityStarter {
}
if (err == ActivityManager.START_SUCCESS && sourceRecord != null
- && sourceRecord.getTaskRecord().voiceSession != null) {
+ && sourceRecord.getTask().voiceSession != null) {
// If this activity is being launched as part of a voice session, we need to ensure
// that it is safe to do so. If the upcoming activity will also be part of the voice
// session, we can only launch it if it has explicitly said it supports the VOICE
@@ -1392,7 +1392,7 @@ class ActivityStarter {
*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+ int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
@@ -1464,7 +1464,7 @@ class ActivityStarter {
*/
private int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+ int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
@@ -1477,7 +1477,7 @@ class ActivityStarter {
mIntent.setFlags(mLaunchFlags);
- final TaskRecord reusedTask = getReusableTask();
+ final Task reusedTask = getReusableTask();
mSupervisor.getLaunchParamsController().calculate(reusedTask != null ? reusedTask : mInTask,
r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
mPreferredDisplayId =
@@ -1493,7 +1493,7 @@ class ActivityStarter {
}
// Compute if there is an existing task that should be used for.
- final TaskRecord targetTask = reusedTask != null ? reusedTask : computeTargetTask();
+ final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
// Check if starting activity on given task or on a new task is allowed.
@@ -1525,11 +1525,11 @@ class ActivityStarter {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
}
if (newTask) {
- final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
- ? mSourceRecord.getTaskRecord() : null;
+ final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+ ? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
if (mService.getLockTaskController().isLockTaskModeViolation(
- mStartActivity.getTaskRecord())) {
+ mStartActivity.getTask())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
@@ -1550,10 +1550,10 @@ class ActivityStarter {
);
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
- mStartActivity.getTaskRecord().mTaskId);
+ mStartActivity.getTask().mTaskId);
}
mStartActivity.logStartActivity(
- EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTaskRecord());
+ EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
@@ -1563,7 +1563,7 @@ class ActivityStarter {
mKeepCurTransition, mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
- mStartActivity.getTaskRecord().topRunningActivityLocked();
+ mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
@@ -1591,36 +1591,36 @@ class ActivityStarter {
mTargetStack, mStartActivity, mOptions);
}
} else if (mStartActivity != null) {
- mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
+ mSupervisor.mRecentTasks.add(mStartActivity.getTask());
}
mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
- mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
+ mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
preferredWindowingMode, mPreferredDisplayId, mTargetStack);
return START_SUCCESS;
}
- private TaskRecord computeTargetTask() {
+ private Task computeTargetTask() {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// A new task should be created instead of using existing one.
return null;
} else if (mSourceRecord != null) {
- return mSourceRecord.getTaskRecord();
+ return mSourceRecord.getTask();
} else if (mInTask != null) {
return mInTask;
} else {
final ActivityRecord top = computeStackFocus(mStartActivity, false /* newTask */,
mLaunchFlags, mOptions).getTopActivity();
if (top != null) {
- return top.getTaskRecord();
+ return top.getTask();
}
}
return null;
}
- private int isAllowedToStart(ActivityRecord r, boolean newTask, TaskRecord targetTask) {
+ private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
if (mStartActivity.packageName == null) {
if (mStartActivity.resultTo != null) {
mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho,
@@ -1666,8 +1666,7 @@ class ActivityStarter {
* - Comply to the specified activity launch flags
* - Determine whether need to add a new activity on top or just brought the task to front.
*/
- private int recycleTask(TaskRecord targetTask, ActivityRecord targetTaskTop,
- TaskRecord reusedTask) {
+ private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
// True if we are clearing top and resetting of a standard (default) launch mode
// ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
final boolean clearTopAndResetStandardLaunchMode =
@@ -1680,7 +1679,7 @@ class ActivityStarter {
// If mStartActivity does not have a task associated with it, associate it with the
// reused activity's task. Do not do so if we're clearing top and resetting for a
// standard launchMode activity.
- if (mStartActivity.getTaskRecord() == null && !clearTopAndResetStandardLaunchMode) {
+ if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
mStartActivity.setTaskForReuse(reusedTask);
clearTaskForReuse = true;
}
@@ -1796,7 +1795,7 @@ class ActivityStarter {
// Don't use mStartActivity.task to show the toast. We're not starting a new activity but
// reusing 'top'. Fields in mStartActivity may not be fully initialized.
- mSupervisor.handleNonResizableTaskIfNeeded(top.getTaskRecord(),
+ mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(),
mLaunchParams.mWindowingMode, mPreferredDisplayId, topStack);
return START_DELIVERED_TO_TOP;
@@ -1806,7 +1805,7 @@ class ActivityStarter {
* Applying the launching flags to the task, which might clear few or all the activities in the
* task.
*/
- private void complyActivityFlags(TaskRecord targetTask, ActivityRecord reusedActivity) {
+ private void complyActivityFlags(Task targetTask, ActivityRecord reusedActivity) {
ActivityRecord targetTaskTop = targetTask.getTopActivity();
final boolean resetTask =
reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0;
@@ -1818,10 +1817,10 @@ class ActivityStarter {
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any existing task with its new
// activity. Well that should not be too hard...
- // Note: we must persist the {@link TaskRecord} first as intentActivity could be
+ // Note: we must persist the {@link Task} first as intentActivity could be
// removed from calling performClearTaskLocked (For example, if it is being brought out
// of history or if it is finished immediately), thus disassociating the task. Also note
- // that mReuseTask is reset as a result of {@link TaskRecord#performClearTaskLocked}
+ // that mReuseTask is reset as a result of {@link Task#performClearTaskLocked}
// launching another activity.
// TODO(b/36119896): We shouldn't trigger activity launches in this path since we are
// already launching one.
@@ -1838,9 +1837,9 @@ class ActivityStarter {
mLaunchFlags);
// The above code can remove {@code reusedActivity} from the task, leading to the
- // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
+ // {@code ActivityRecord} removing its reference to the {@code Task}. The task
// reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
- if (targetTaskTop.getTaskRecord() == null) {
+ if (targetTaskTop.getTask() == null) {
targetTask.addChild(targetTaskTop);
}
@@ -1848,7 +1847,7 @@ class ActivityStarter {
if (top.isRootOfTask()) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
- top.getTaskRecord().setIntent(mStartActivity);
+ top.getTask().setIntent(mStartActivity);
}
deliverNewIntent(top);
} else {
@@ -1873,7 +1872,7 @@ class ActivityStarter {
final ActivityRecord act = targetTask.findActivityInHistoryLocked(
mStartActivity);
if (act != null) {
- final TaskRecord task = act.getTaskRecord();
+ final Task task = act.getTask();
task.moveActivityToFrontLocked(act);
act.updateOptionsLocked(mOptions);
deliverNewIntent(act);
@@ -1894,7 +1893,7 @@ class ActivityStarter {
// activity in the task is the root activity, deliver this new intent to it if it
// desires.
if (targetTaskTop.isRootOfTask()) {
- targetTaskTop.getTaskRecord().setIntent(mStartActivity);
+ targetTaskTop.getTask().setIntent(mStartActivity);
}
deliverNewIntent(targetTaskTop);
} else if (!targetTask.isSameIntentFilter(mStartActivity)) {
@@ -1968,7 +1967,7 @@ class ActivityStarter {
}
}
- private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+ private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean restrictedBgActivity) {
@@ -2036,7 +2035,7 @@ class ActivityStarter {
if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
r.mTaskOverlay = true;
if (!mOptions.canTaskOverlayResume()) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(
+ final Task task = mRootActivityContainer.anyTaskForId(
mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
if (top != null && !top.isState(RESUMED)) {
@@ -2210,7 +2209,7 @@ class ActivityStarter {
// example, if this method is being called for processing a pending activity launch, it
// is possible that the activity has been removed from the task after the launch was
// enqueued.
- final TaskRecord sourceTask = mSourceRecord.getTaskRecord();
+ final Task sourceTask = mSourceRecord.getTask();
mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
}
mSourceRecord = null;
@@ -2221,7 +2220,7 @@ class ActivityStarter {
* Decide whether the new activity should be inserted into an existing task. Returns null
* if not or an ActivityRecord with the task into which the new activity should be added.
*/
- private TaskRecord getReusableTask() {
+ private Task getReusableTask() {
// We may want to try to place the new activity in to an existing task. We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
@@ -2236,7 +2235,7 @@ class ActivityStarter {
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
- TaskRecord launchTask = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId());
+ Task launchTask = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId());
if (launchTask != null) {
return launchTask;
}
@@ -2265,7 +2264,7 @@ class ActivityStarter {
intentActivity = null;
}
- return intentActivity != null ? intentActivity.getTaskRecord() : null;
+ return intentActivity != null ? intentActivity.getTask() : null;
}
/**
@@ -2286,8 +2285,8 @@ class ActivityStarter {
final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
- final TaskRecord topTask = curTop != null ? curTop.getTaskRecord() : null;
- differentTopTask = topTask != intentActivity.getTaskRecord()
+ final Task topTask = curTop != null ? curTop.getTask() : null;
+ differentTopTask = topTask != intentActivity.getTask()
|| (focusStack != null && topTask != focusStack.topTask());
} else {
// The existing task should always be different from those in other displays.
@@ -2297,14 +2296,14 @@ class ActivityStarter {
if (differentTopTask && !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
- mSourceStack.getTopActivity().getTaskRecord()
- == mSourceRecord.getTaskRecord())) {
+ mSourceStack.getTopActivity().getTask()
+ == mSourceRecord.getTask())) {
// We really do want to push this one into the user's face, right now.
if (mLaunchTaskBehind && mSourceRecord != null) {
- intentActivity.setTaskToAffiliateWith(mSourceRecord.getTaskRecord());
+ intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
}
- final TaskRecord intentTask = intentActivity.getTaskRecord();
+ final Task intentTask = intentActivity.getTask();
final ActivityStack launchStack =
getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions);
if (launchStack == null || launchStack == mTargetStack) {
@@ -2336,7 +2335,7 @@ class ActivityStarter {
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
- intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
+ intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentToDisplay");
mMovedToFront = true;
@@ -2346,7 +2345,7 @@ class ActivityStarter {
// For example, the activity may have been initially started with an intent
// which placed it in the fullscreen stack. To ensure the proper handling of
// the activity based on home stack assumptions, we must move it over.
- intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
+ intentActivity.getTask().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentingHome");
mMovedToFront = true;
@@ -2365,7 +2364,7 @@ class ActivityStarter {
// Need to update mTargetStack because if task was moved out of it, the original stack may
// be destroyed.
mTargetStack = intentActivity.getActivityStack();
- mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTaskRecord(),
+ mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
}
@@ -2378,19 +2377,19 @@ class ActivityStarter {
mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
}
- private void setNewTask(TaskRecord taskToAffiliate) {
+ private void setNewTask(Task taskToAffiliate) {
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
- final TaskRecord task = mTargetStack.createTaskRecord(
+ final Task task = mTargetStack.createTask(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
- updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);
+ updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
if (DEBUG_TASKS) {
Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in new task " + mStartActivity.getTaskRecord());
+ + " in new task " + mStartActivity.getTask());
}
if (taskToAffiliate != null) {
@@ -2403,14 +2402,14 @@ class ActivityStarter {
return;
}
- activity.logStartActivity(AM_NEW_INTENT, activity.getTaskRecord());
+ activity.logStartActivity(AM_NEW_INTENT, activity.getTask());
activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
mIntentDelivered = true;
}
@VisibleForTesting
- void updateBounds(TaskRecord task, Rect bounds) {
+ void updateBounds(Task task, Rect bounds) {
if (bounds.isEmpty()) {
return;
}
@@ -2423,8 +2422,8 @@ class ActivityStarter {
}
}
- private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
- if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
+ private void addOrReparentStartingActivity(Task parent, String reason) {
+ if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
parent.addChild(mStartActivity);
} else {
mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
@@ -2460,7 +2459,7 @@ class ActivityStarter {
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
ActivityOptions aOptions) {
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
if (stack != null) {
return stack;
@@ -2542,7 +2541,7 @@ class ActivityStarter {
&& (mPreferredDisplayId == focusedStack.mDisplayId);
}
- private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+ private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
// We are reusing a task, keep the stack!
if (mReuseTask != null) {
@@ -2753,7 +2752,7 @@ class ActivityStarter {
return this;
}
- ActivityStarter setInTask(TaskRecord inTask) {
+ ActivityStarter setInTask(Task inTask) {
mRequest.inTask = inTask;
return this;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0488a3b7065b..cce005bc859c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -229,7 +229,7 @@ public abstract class ActivityTaskManagerInternal {
public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ int userId, Task inTask, String reason, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart);
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 32f46520f821..3ef848cb0106 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -117,9 +117,9 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_ONLY;
import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
import android.Manifest;
import android.annotation.IntDef;
@@ -1572,7 +1572,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return true;
}
// Keep track of the root activity of the task before we finish it
- final TaskRecord tr = r.getTaskRecord();
+ final Task tr = r.getTask();
final ActivityRecord rootR = tr.getRootActivity();
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
@@ -1994,7 +1994,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null) {
return false;
}
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
int index = task.mChildren.lastIndexOf(r);
if (index > 0) {
ActivityRecord under = task.getChildAt(index - 1);
@@ -2086,7 +2086,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
return;
@@ -2196,7 +2196,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long origId = Binder.clearCallingIdentity();
try {
int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+ final Task task = mRootActivityContainer.anyTaskForId(taskId);
if (task != null) {
return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
}
@@ -2214,7 +2214,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Rect rect = new Rect();
try {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
@@ -2237,7 +2237,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
enforceCallerIsRecentsOrHasPermission(
MANAGE_ACTIVITY_STACKS, "getTaskDescription()");
- final TaskRecord tr = mRootActivityContainer.anyTaskForId(id,
+ final Task tr = mRootActivityContainer.anyTaskForId(id,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
return tr.getTaskDescription();
@@ -2257,7 +2257,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
@@ -2335,7 +2335,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// 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.
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
mTaskChangeNotificationController
.notifyBackPressedOnTaskRoot(task.getTaskInfo());
} else {
@@ -2393,7 +2393,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
try {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+ final Task task = mRootActivityContainer.anyTaskForId(taskId);
if (task == null) {
Slog.d(TAG, "Could not find task for id: "+ taskId);
SafeActivityOptions.abort(options);
@@ -2573,7 +2573,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+ final Task task = mRootActivityContainer.anyTaskForId(taskId);
if (task == null) {
Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
return;
@@ -2685,7 +2685,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
@@ -2817,7 +2817,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null) {
return;
}
- startLockTaskModeLocked(r.getTaskRecord(), false /* isSystemCaller */);
+ startLockTaskModeLocked(r.getTask(), false /* isSystemCaller */);
}
}
@@ -2828,7 +2828,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
return;
@@ -2850,7 +2850,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null) {
return;
}
- stopLockTaskModeInternal(r.getTaskRecord(), false /* isSystemCaller */);
+ stopLockTaskModeInternal(r.getTask(), false /* isSystemCaller */);
}
}
@@ -2864,7 +2864,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
stopLockTaskModeInternal(null, true /* isSystemCaller */);
}
- private void startLockTaskModeLocked(@Nullable TaskRecord task, boolean isSystemCaller) {
+ private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
@@ -2893,7 +2893,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- private void stopLockTaskModeInternal(@Nullable TaskRecord task, boolean isSystemCaller) {
+ private void stopLockTaskModeInternal(@Nullable Task task, boolean isSystemCaller) {
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
@@ -2943,7 +2943,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
r.setTaskDescription(td);
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
task.updateTaskDescription();
}
}
@@ -2999,7 +2999,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isTopOfTask(IBinder token) {
synchronized (mGlobalLock) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
- return r != null && r.getTaskRecord().getTopActivity() == r;
+ return r != null && r.getTask().getTopActivity() == r;
}
}
@@ -3038,7 +3038,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
if (structure != null) {
// Pre-fill the task/activity component for all assist data receivers
- structure.setTaskId(pae.activity.getTaskRecord().mTaskId);
+ structure.setTaskId(pae.activity.getTask().mTaskId);
structure.setActivityComponent(pae.activity.mActivityComponent);
structure.setHomeActivity(pae.isHome);
}
@@ -3065,7 +3065,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// Caller wants result sent back to them.
sendBundle = new Bundle();
sendBundle.putInt(ActivityTaskManagerInternal.ASSIST_TASK_ID,
- pae.activity.getTaskRecord().mTaskId);
+ pae.activity.getTask().mTaskId);
sendBundle.putBinder(ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID,
pae.activity.assistToken);
sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
@@ -3153,7 +3153,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final ActivityStack stack = r.getActivityStack();
- final TaskRecord task = stack.createTaskRecord(
+ final Task task = stack.createTask(
mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), ainfo, intent,
null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
if (!mRecentTasks.addToBottom(task)) {
@@ -3182,7 +3182,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(
+ final Task task = mRootActivityContainer.anyTaskForId(
taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
@@ -3198,7 +3198,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
@@ -3243,7 +3243,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private void sanitizeAndApplyConfigChange(ConfigurationContainer container,
WindowContainerTransaction.Change change) {
- if (!(container instanceof TaskRecord)) {
+ if (!(container instanceof Task)) {
throw new RuntimeException("Invalid token in task transaction");
}
// The "client"-facing API should prevent bad changes; however, just in case, sanitize
@@ -3884,7 +3884,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
+ taskId + " in stackId=" + stackId + " at position=" + position);
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+ final Task task = mRootActivityContainer.anyTaskForId(taskId);
if (task == null) {
throw new IllegalArgumentException("positionTaskInStack: no task for id="
+ taskId);
@@ -4359,7 +4359,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
- if (mRunningVoice != null || activity.getTaskRecord().voiceSession != null
+ if (mRunningVoice != null || activity.getTask().voiceSession != null
|| activity.voiceSession != null) {
Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
return;
@@ -4469,7 +4469,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+ final Task task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
@@ -4495,7 +4495,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution,
boolean restoreFromDisk) {
- final TaskRecord task;
+ final Task task;
synchronized (mGlobalLock) {
task = mRootActivityContainer.anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
@@ -4820,7 +4820,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
/** Pokes the task persister. */
- void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+ void notifyTaskPersisterLocked(Task task, boolean flush) {
mRecentTasks.notifyTaskPersisterLocked(task, flush);
}
@@ -4977,7 +4977,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String[] newArgs = new String[args.length - opti];
System.arraycopy(args, opti, newArgs, 0, args.length - opti);
- TaskRecord lastTask = null;
+ Task lastTask = null;
boolean needSep = false;
for (int i = activities.size() - 1; i >= 0; i--) {
ActivityRecord r = activities.get(i);
@@ -4986,7 +4986,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
needSep = true;
synchronized (mGlobalLock) {
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
if (lastTask != task) {
lastTask = task;
pw.print("TASK "); pw.print(lastTask.affinity);
@@ -5403,7 +5403,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** Update AMS states when an activity is resumed. */
void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
if (task.isActivityTypeStandard()) {
if (mCurAppTimeTracker != r.appTimeTracker) {
// We are switching app tracking. Complete the current one.
@@ -5435,7 +5435,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (mLastResumedActivity != null) {
final IVoiceInteractionSession session;
- final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTaskRecord();
+ final Task lastResumedActivityTask = mLastResumedActivity.getTask();
if (lastResumedActivityTask != null
&& lastResumedActivityTask.voiceSession != null) {
session = lastResumedActivityTask.voiceSession;
@@ -5536,7 +5536,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
void updateActivityUsageStats(ActivityRecord activity, int event) {
ComponentName taskRoot = null;
- final TaskRecord task = activity.getTaskRecord();
+ final Task task = activity.getTask();
if (task != null) {
final ActivityRecord rootActivity = task.getRootActivity();
if (rootActivity != null) {
@@ -6141,7 +6141,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
- int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+ int userId, Task inTask, String reason, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
synchronized (mGlobalLock) {
@@ -6570,13 +6570,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public ActivityTokens getTopActivityForTask(int taskId) {
synchronized (mGlobalLock) {
- final TaskRecord taskRecord = mRootActivityContainer.anyTaskForId(taskId);
- if (taskRecord == null) {
+ final Task task = mRootActivityContainer.anyTaskForId(taskId);
+ if (task == null) {
Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
+ " Requested task not found");
return null;
}
- final ActivityRecord activity = taskRecord.getTopActivity();
+ final ActivityRecord activity = task.getTopActivity();
if (activity == null) {
Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
+ " Requested activity not found");
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index c5e190dc59cd..93a22caa2757 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -79,12 +79,12 @@ class AppTaskImpl extends IAppTask.Stub {
synchronized (mService.mGlobalLock) {
long origId = Binder.clearCallingIdentity();
try {
- TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+ Task task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
- if (tr == null) {
+ if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
- return mService.getRecentTasks().createRecentTaskInfo(tr);
+ return mService.getRecentTasks().createRecentTaskInfo(task);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -136,12 +136,12 @@ class AppTaskImpl extends IAppTask.Stub {
checkCaller();
int callingUser = UserHandle.getCallingUserId();
- TaskRecord tr;
+ Task task;
IApplicationThread appThread;
synchronized (mService.mGlobalLock) {
- tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+ task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
- if (tr == null) {
+ if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
appThread = IApplicationThread.Stub.asInterface(whoThread);
@@ -156,7 +156,7 @@ class AppTaskImpl extends IAppTask.Stub {
.setResolvedType(resolvedType)
.setActivityOptions(bOptions)
.setUserId(callingUser)
- .setInTask(tr)
+ .setInTask(task)
.execute();
}
@@ -167,12 +167,12 @@ class AppTaskImpl extends IAppTask.Stub {
synchronized (mService.mGlobalLock) {
long origId = Binder.clearCallingIdentity();
try {
- TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+ Task task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
- if (tr == null) {
+ if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
- Intent intent = tr.getBaseIntent();
+ Intent intent = task.getBaseIntent();
if (exclude) {
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
} else {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index bef6af350269..ff1b42377f5f 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -688,15 +688,16 @@ public class AppTransitionController {
* compare z-order.
*
* @param apps The list of apps to search.
- * @param ignoreHidden If set to true, ignores apps that are {@link ActivityRecord#isHidden}.
+ * @param ignoreInvisible If set to true, ignores apps that are not
+ * {@link ActivityRecord#isVisible}.
* @return The top {@link ActivityRecord}.
*/
- private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreHidden) {
+ private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) {
int topPrefixOrderIndex = Integer.MIN_VALUE;
ActivityRecord topApp = null;
for (int i = apps.size() - 1; i >= 0; i--) {
final ActivityRecord app = apps.valueAt(i);
- if (ignoreHidden && app.isHidden()) {
+ if (ignoreInvisible && !app.isVisible()) {
continue;
}
final int prefixOrderIndex = app.getPrefixOrderIndex();
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
deleted file mode 100644
index b73b481075ae..000000000000
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2014 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 static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
-import android.view.SurfaceControl;
-
-import java.util.function.Supplier;
-
-class CircularDisplayMask {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "CircularDisplayMask" : TAG_WM;
-
- // size of the chin
- private int mScreenOffset = 0;
- // Display dimensions
- private Point mScreenSize;
-
- private final SurfaceControl mSurfaceControl;
- private final Surface mSurface;
- private int mLastDW;
- private int mLastDH;
- private boolean mDrawNeeded;
- private Paint mPaint;
- private int mRotation;
- private boolean mVisible;
- private boolean mDimensionsUnequal = false;
- private int mMaskThickness;
-
- CircularDisplayMask(Supplier<Surface> surfaceFactory, DisplayContent dc, int zOrder,
- int screenOffset, int maskThickness, SurfaceControl.Transaction t) {
- final Display display = dc.getDisplay();
- mSurface = surfaceFactory.get();
- mScreenSize = new Point();
- display.getSize(mScreenSize);
- if (mScreenSize.x != mScreenSize.y + screenOffset) {
- Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() +
- "are not equal, circularMask will not be drawn.");
- mDimensionsUnequal = true;
- }
-
- SurfaceControl ctrl = null;
- try {
- ctrl = dc.makeOverlay()
- .setName("CircularDisplayMask")
- .setBufferSize(mScreenSize.x, mScreenSize.y) // not a typo
- .setFormat(PixelFormat.TRANSLUCENT)
- .build();
-
- t.setLayerStack(ctrl, display.getLayerStack());
- t.setLayer(ctrl, zOrder);
- t.setPosition(ctrl, 0, 0);
- t.show(ctrl);
- mSurface.copyFrom(ctrl);
- } catch (OutOfResourcesException e) {
- }
- mSurfaceControl = ctrl;
- mDrawNeeded = true;
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
- mScreenOffset = screenOffset;
- mMaskThickness = maskThickness;
- }
-
- private void drawIfNeeded(SurfaceControl.Transaction t) {
- if (!mDrawNeeded || !mVisible || mDimensionsUnequal) {
- return;
- }
- mDrawNeeded = false;
-
- Rect dirty = new Rect(0, 0, mScreenSize.x, mScreenSize.y);
- Canvas c = null;
- try {
- c = mSurface.lockCanvas(dirty);
- } catch (IllegalArgumentException e) {
- } catch (Surface.OutOfResourcesException e) {
- }
- if (c == null) {
- return;
- }
- switch (mRotation) {
- case Surface.ROTATION_0:
- case Surface.ROTATION_90:
- // chin bottom or right
- t.setPosition(mSurfaceControl, 0, 0);
- break;
- case Surface.ROTATION_180:
- // chin top
- t.setPosition(mSurfaceControl, 0, -mScreenOffset);
- break;
- case Surface.ROTATION_270:
- // chin left
- t.setPosition(mSurfaceControl, -mScreenOffset, 0);
- break;
- }
-
- int circleRadius = mScreenSize.x / 2;
- c.drawColor(Color.BLACK);
-
- // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the
- // display edges.
- c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint);
- mSurface.unlockCanvasAndPost(c);
- }
-
- // Note: caller responsible for being inside
- // Surface.openTransaction() / closeTransaction()
- public void setVisibility(boolean on, SurfaceControl.Transaction t) {
- if (mSurfaceControl == null) {
- return;
- }
- mVisible = on;
- drawIfNeeded(t);
- if (on) {
- t.show(mSurfaceControl);
- } else {
- t.hide(mSurfaceControl);
- }
- }
-
- void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) {
- if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
- return;
- }
- mLastDW = dw;
- mLastDH = dh;
- mDrawNeeded = true;
- mRotation = rotation;
- drawIfNeeded(t);
- }
-
-}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7cca08f6cab0..6eb9dba254d8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -652,12 +652,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
+ " config reported=" + w.isLastConfigReportedToClient());
final ActivityRecord activity = w.mActivityRecord;
if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility
- + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden()
- + " hiddenRequested=" + (activity != null && activity.hiddenRequested)
+ + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
+ + " visibleRequested=" + (activity != null && activity.mVisibleRequested)
+ " parentHidden=" + w.isParentWindowHidden());
else Slog.v(TAG, " VIS: mViewVisibility=" + w.mViewVisibility
- + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden()
- + " hiddenRequested=" + (activity != null && activity.hiddenRequested)
+ + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
+ + " visibleRequested=" + (activity != null && activity.mVisibleRequested)
+ " parentHidden=" + w.isParentWindowHidden());
}
@@ -1173,6 +1173,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (!isReady() || mActivityDisplay == null) {
return;
}
+ if (mDisplayRotation.isWaitingForRemoteRotation()) {
+ return;
+ }
final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked();
if (configUpdated) {
return;
@@ -2257,7 +2260,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
boolean pointWithinAppWindow(int x, int y) {
final int[] targetWindowType = {-1};
- final Consumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
+ final PooledConsumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
if (targetWindowType[0] != -1) {
return;
}
@@ -2268,7 +2271,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}, PooledLambda.__(WindowState.class), mTmpRect);
forAllWindows(fn, true /* traverseTopToBottom */);
- ((PooledConsumer) fn).recycle();
+ fn.recycle();
return FIRST_APPLICATION_WINDOW <= targetWindowType[0]
&& targetWindowType[0] <= LAST_APPLICATION_WINDOW;
}
@@ -2391,6 +2394,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWindowingLayer.release();
mOverlayLayer.release();
mInputMonitor.onDisplayRemoved();
+ mWmService.mDisplayNotificationController.dispatchDisplayRemoved(mActivityDisplay);
} finally {
mDisplayReady = false;
mRemovingDisplay = false;
@@ -3057,7 +3061,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
wsa.destroySurface();
mWmService.mForceRemoves.add(w);
mTmpWindow = w;
- } else if (w.mActivityRecord != null && w.mActivityRecord.isClientHidden()) {
+ } else if (w.mActivityRecord != null && !w.mActivityRecord.isClientVisible()) {
Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+ w + " surface=" + wsa.mSurfaceController
+ " token=" + w.mActivityRecord);
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index dc6b49127f7b..6b47c8a820d0 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -39,20 +39,11 @@ public class DisplayFrames {
public final int mDisplayId;
/**
- * The current size of the screen; really; extends into the overscan area of the screen and
- * doesn't account for any system elements like the status bar.
- */
- public final Rect mOverscan = new Rect();
-
- /**
* The current visible size of the screen; really; (ir)regardless of whether the status bar can
* be hidden but not extending into the overscan area.
*/
public final Rect mUnrestricted = new Rect();
- /** Like mOverscan*, but allowed to move into the overscan region where appropriate. */
- public final Rect mRestrictedOverscan = new Rect();
-
/**
* The current size of the screen; these may be different than (0,0)-(dw,dh) if the status bar
* can't be hidden; in that case it effectively carves out that area of the display from all
@@ -109,8 +100,6 @@ public class DisplayFrames {
*/
public final Rect mDisplayCutoutSafe = new Rect();
- private final Rect mDisplayInfoOverscan = new Rect();
- private final Rect mRotatedDisplayInfoOverscan = new Rect();
public int mDisplayWidth;
public int mDisplayHeight;
@@ -125,43 +114,13 @@ public class DisplayFrames {
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
mRotation = info.rotation;
- mDisplayInfoOverscan.set(
- info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
mDisplayInfoCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
}
public void onBeginLayout() {
- switch (mRotation) {
- case ROTATION_90:
- mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
- mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.right;
- mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.bottom;
- mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.left;
- break;
- case ROTATION_180:
- mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.right;
- mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.bottom;
- mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.left;
- mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.top;
- break;
- case ROTATION_270:
- mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.bottom;
- mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.left;
- mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.top;
- mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.right;
- break;
- default:
- mRotatedDisplayInfoOverscan.set(mDisplayInfoOverscan);
- break;
- }
-
- mRestrictedOverscan.set(0, 0, mDisplayWidth, mDisplayHeight);
- mOverscan.set(mRestrictedOverscan);
- mSystem.set(mRestrictedOverscan);
- mUnrestricted.set(mRotatedDisplayInfoOverscan);
- mUnrestricted.right = mDisplayWidth - mUnrestricted.right;
- mUnrestricted.bottom = mDisplayHeight - mUnrestricted.bottom;
+ mUnrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
mRestricted.set(mUnrestricted);
+ mSystem.set(mUnrestricted);
mDock.set(mUnrestricted);
mContent.set(mUnrestricted);
mVoiceContent.set(mUnrestricted);
@@ -175,16 +134,16 @@ public class DisplayFrames {
if (!mDisplayCutout.getDisplayCutout().isEmpty()) {
final DisplayCutout c = mDisplayCutout.getDisplayCutout();
if (c.getSafeInsetLeft() > 0) {
- mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
+ mDisplayCutoutSafe.left = mUnrestricted.left + c.getSafeInsetLeft();
}
if (c.getSafeInsetTop() > 0) {
- mDisplayCutoutSafe.top = mRestrictedOverscan.top + c.getSafeInsetTop();
+ mDisplayCutoutSafe.top = mUnrestricted.top + c.getSafeInsetTop();
}
if (c.getSafeInsetRight() > 0) {
- mDisplayCutoutSafe.right = mRestrictedOverscan.right - c.getSafeInsetRight();
+ mDisplayCutoutSafe.right = mUnrestricted.right - c.getSafeInsetRight();
}
if (c.getSafeInsetBottom() > 0) {
- mDisplayCutoutSafe.bottom = mRestrictedOverscan.bottom - c.getSafeInsetBottom();
+ mDisplayCutoutSafe.bottom = mUnrestricted.bottom - c.getSafeInsetBottom();
}
}
}
@@ -210,12 +169,8 @@ public class DisplayFrames {
dumpFrame(mSystem, "mSystem", myPrefix, pw);
dumpFrame(mContent, "mContent", myPrefix, pw);
dumpFrame(mVoiceContent, "mVoiceContent", myPrefix, pw);
- dumpFrame(mOverscan, "mOverscan", myPrefix, pw);
- dumpFrame(mRestrictedOverscan, "mRestrictedOverscan", myPrefix, pw);
dumpFrame(mRestricted, "mRestricted", myPrefix, pw);
dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
- dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
- dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6a6b2517e1a5..f8c1ad951fc3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -163,7 +163,6 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.view.AppearanceRegion;
@@ -294,9 +293,6 @@ public class DisplayPolicy {
private boolean mIsFreeformWindowOverlappingWithNavBar;
- /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
- @Px private int mWindowOutsetBottom;
-
private final StatusBarController mStatusBarController;
private final BarController mNavigationBarController;
@@ -1209,7 +1205,6 @@ public class DisplayPolicy {
* @param outContentInsets The areas covered by system windows, expressed as positive insets.
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
- * @param outOutsets The areas that are not real display, but we would like to treat as such.
* @param outDisplayCutout The area that has been cut away from the display.
* @return Whether to always consume the system bars.
* See {@link #areSystemBarsForcedShownLw(WindowState)}.
@@ -1217,28 +1212,11 @@ public class DisplayPolicy {
public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
+ DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int pfl = attrs.privateFlags;
final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
- final int displayRotation = displayFrames.mRotation;
-
- final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
- if (useOutsets) {
- int outset = mWindowOutsetBottom;
- if (outset > 0) {
- if (displayRotation == Surface.ROTATION_0) {
- outOutsets.bottom += outset;
- } else if (displayRotation == Surface.ROTATION_90) {
- outOutsets.right += outset;
- } else if (displayRotation == Surface.ROTATION_180) {
- outOutsets.top += outset;
- } else if (displayRotation == Surface.ROTATION_270) {
- outOutsets.left += outset;
- }
- }
- }
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -1268,8 +1246,8 @@ public class DisplayPolicy {
} else {
cf = displayFrames.mStable;
}
- } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
- cf = displayFrames.mOverscan;
+ } else if ((fl & FLAG_FULLSCREEN) != 0) {
+ cf = displayFrames.mUnrestricted;
} else {
cf = displayFrames.mCurrent;
}
@@ -1312,11 +1290,6 @@ public class DisplayPolicy {
return impliedFlags;
}
- private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
- return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
- }
-
private final Runnable mClearHideNavigationFlag = new Runnable() {
@Override
public void run() {
@@ -1482,11 +1455,9 @@ public class DisplayPolicy {
w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
- displayFrames.mUnrestricted /* overscanFrame */,
displayFrames.mUnrestricted /* contentFrame */,
displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
- displayFrames.mUnrestricted /* stableFrame */,
- displayFrames.mUnrestricted /* outsetFrame */);
+ displayFrames.mUnrestricted /* stableFrame */);
w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
w.computeFrameLw();
final Rect frame = w.getFrameLw();
@@ -1530,7 +1501,6 @@ public class DisplayPolicy {
displayFrames.mVoiceContent.set(dockFrame);
displayFrames.mSystem.set(dockFrame);
displayFrames.mContent.set(dockFrame);
- displayFrames.mRestrictedOverscan.set(dockFrame);
}
private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
@@ -1544,9 +1514,9 @@ public class DisplayPolicy {
final WindowFrames windowFrames = mStatusBar.getWindowFrames();
windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
- displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
+ displayFrames.mStable /* contentFrame */,
displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
- displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
+ displayFrames.mStable /* stableFrame */);
windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
// Let the status bar determine its size.
@@ -1630,8 +1600,7 @@ public class DisplayPolicy {
mNavigationBarController.setBarShowingLw(true);
} else if (navVisible) {
mNavigationBarController.setBarShowingLw(true);
- dockFrame.bottom = displayFrames.mRestricted.bottom =
- displayFrames.mRestrictedOverscan.bottom = top;
+ dockFrame.bottom = displayFrames.mRestricted.bottom = top;
} else {
// We currently want to hide the navigation UI - unless we expanded the status bar.
mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1653,8 +1622,7 @@ public class DisplayPolicy {
mNavigationBarController.setBarShowingLw(true);
} else if (navVisible) {
mNavigationBarController.setBarShowingLw(true);
- dockFrame.right = displayFrames.mRestricted.right =
- displayFrames.mRestrictedOverscan.right = left;
+ dockFrame.right = displayFrames.mRestricted.right = left;
} else {
// We currently want to hide the navigation UI - unless we expanded the status bar.
mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1676,8 +1644,7 @@ public class DisplayPolicy {
mNavigationBarController.setBarShowingLw(true);
} else if (navVisible) {
mNavigationBarController.setBarShowingLw(true);
- dockFrame.left = displayFrames.mRestricted.left =
- displayFrames.mRestrictedOverscan.left = right;
+ dockFrame.left = displayFrames.mRestricted.left = right;
} else {
// We currently want to hide the navigation UI - unless we expanded the status bar.
mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
@@ -1699,11 +1666,10 @@ public class DisplayPolicy {
// And compute the final frame.
sTmpRect.setEmpty();
mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
- navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
+ navigationFrame /* displayFrame */,
displayFrames.mDisplayCutoutSafe /* contentFrame */,
navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
- navigationFrame /* stableFrame */,
- displayFrames.mDisplayCutoutSafe /* outsetFrame */);
+ navigationFrame /* stableFrame */);
mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
mNavigationBar.computeFrameLw();
mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
@@ -1713,7 +1679,7 @@ public class DisplayPolicy {
}
private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
+ boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
DisplayFrames displayFrames) {
if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
// Here's a special case: if the child window is not the 'dock window'
@@ -1725,29 +1691,25 @@ public class DisplayPolicy {
// compute the frames that would be appropriate without the dock.
vf.set(displayFrames.mDock);
cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
df.set(displayFrames.mDock);
} else {
- // In case we forced the window to draw behind the navigation bar, restrict df/of to
- // DF.RestrictedOverscan to simulate old compat behavior.
+ // In case we forced the window to draw behind the navigation bar, restrict df to
+ // DF.Restricted to simulate old compat behavior.
Rect parentDisplayFrame = attached.getDisplayFrameLw();
- Rect parentOverscan = attached.getOverscanFrameLw();
final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
&& (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
&& (attachedAttrs.systemUiVisibility
& SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
- parentOverscan = new Rect(parentOverscan);
- parentOverscan.intersect(displayFrames.mRestrictedOverscan);
parentDisplayFrame = new Rect(parentDisplayFrame);
- parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
+ parentDisplayFrame.intersect(displayFrames.mRestricted);
}
// The effective display frame of the attached window depends on whether it is taking
// care of insetting its content. If not, we need to use the parent's content frame so
// that the entire window is positioned within that content. Otherwise we can use the
- // overscan frame and let the attached window take care of positioning its content
+ // parent display frame and let the attached window take care of positioning its content
// appropriately.
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
// Set the content frame of the attached window to the parent's decor frame
@@ -1755,7 +1717,7 @@ public class DisplayPolicy {
// setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
// Otherwise, use the overscan frame.
cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrameLw() : parentOverscan);
+ ? attached.getContentFrameLw() : parentDisplayFrame);
} else {
// If the window is resizing, then we want to base the content frame on our attached
// content frame to resize...however, things can be tricky if the attached window is
@@ -1770,7 +1732,6 @@ public class DisplayPolicy {
}
}
df.set(insetDecors ? parentDisplayFrame : cf);
- of.set(insetDecors ? parentOverscan : cf);
vf.set(attached.getVisibleFrameLw());
}
// The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
@@ -1820,7 +1781,6 @@ public class DisplayPolicy {
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();
- final boolean isDefaultDisplay = win.isDefaultDisplay();
final int type = attrs.type;
final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -1831,11 +1791,9 @@ public class DisplayPolicy {
final WindowFrames windowFrames = win.getWindowFrames();
- windowFrames.setHasOutsets(false);
sTmpLastParentFrame.set(windowFrames.mParentFrame);
final Rect pf = windowFrames.mParentFrame;
final Rect df = windowFrames.mDisplayFrame;
- final Rect of = windowFrames.mOverscanFrame;
final Rect cf = windowFrames.mContentFrame;
final Rect vf = windowFrames.mVisibleFrame;
final Rect dcf = windowFrames.mDecorFrame;
@@ -1860,21 +1818,20 @@ public class DisplayPolicy {
if (type == TYPE_INPUT_METHOD) {
vf.set(displayFrames.mDock);
cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
df.set(displayFrames.mDock);
windowFrames.mParentFrame.set(displayFrames.mDock);
// IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
+ pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
// ...with content insets above the nav bar
cf.bottom = vf.bottom = displayFrames.mStable.bottom;
if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
// The status bar forces the navigation bar while it's visible. Make sure the IME
// avoids the navigation bar in that case.
if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = of.right = cf.right = vf.right =
+ pf.right = df.right = cf.right = vf.right =
displayFrames.mStable.right;
} else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
+ pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
}
}
@@ -1897,7 +1854,6 @@ public class DisplayPolicy {
// IM dock windows always go to the bottom of the screen.
attrs.gravity = Gravity.BOTTOM;
} else if (type == TYPE_VOICE_INTERACTION) {
- of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
@@ -1911,9 +1867,8 @@ public class DisplayPolicy {
vf.set(cf);
}
} else if (type == TYPE_WALLPAPER) {
- layoutWallpaper(displayFrames, pf, df, of, cf);
+ layoutWallpaper(displayFrames, pf, df, cf);
} else if (win == mStatusBar) {
- of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
cf.set(displayFrames.mStable);
@@ -1967,7 +1922,7 @@ public class DisplayPolicy {
if (attached != null) {
// If this window is attached to another, our display
// frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
+ setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
displayFrames);
} else {
if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
@@ -1977,24 +1932,17 @@ public class DisplayPolicy {
//
// However, they should still dodge the navigation bar if it exists.
- pf.left = df.left = of.left = hasNavBar
+ pf.left = df.left = hasNavBar
? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
- pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
- pf.right = df.right = of.right = hasNavBar
+ pf.top = df.top = displayFrames.mUnrestricted.top;
+ pf.right = df.right = hasNavBar
? displayFrames.mRestricted.right
: displayFrames.mUnrestricted.right;
- pf.bottom = df.bottom = of.bottom = hasNavBar
+ pf.bottom = df.bottom = hasNavBar
? displayFrames.mRestricted.bottom
: displayFrames.mUnrestricted.bottom;
if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
- } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
- // Asking to layout into the overscan region, so give it that pure
- // unrestricted area.
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
} else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
|| type == TYPE_VOLUME_OVERLAY
@@ -2003,19 +1951,11 @@ public class DisplayPolicy {
// extend into the unrestricted overscan screen area. We only do this for
// application windows and certain system windows to ensure no window that
// can be above the nav bar can do this.
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- // We need to tell the app about where the frame inside the overscan is, so
- // it can inset its content by that amount -- it didn't ask to actually
- // extend itself into the overscan region.
- of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
} else {
- df.set(displayFrames.mRestrictedOverscan);
- pf.set(displayFrames.mRestrictedOverscan);
- // We need to tell the app about where the frame inside the overscan
- // is, so it can inset its content by that amount -- it didn't ask
- // to actually extend itself into the overscan region.
- of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
}
if ((fl & FLAG_FULLSCREEN) == 0) {
@@ -2053,19 +1993,17 @@ public class DisplayPolicy {
// gets everything, period.
if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
if (hasNavBar) {
- pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
- pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
- pf.bottom = df.bottom = of.bottom = cf.bottom =
+ pf.left = df.left = cf.left = displayFrames.mDock.left;
+ pf.right = df.right = cf.right = displayFrames.mRestricted.right;
+ pf.bottom = df.bottom = cf.bottom =
displayFrames.mRestricted.bottom;
}
if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
} else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
// The navigation bar has Real Ultimate Power.
- of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
@@ -2073,24 +2011,14 @@ public class DisplayPolicy {
&& ((fl & FLAG_FULLSCREEN) != 0)) {
// Fullscreen secure system overlays get what they ask for. Screenshot region
// selection overlay should also expand to full screen.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
+ cf.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
} else if (type == TYPE_BOOT_PROGRESS) {
// Boot progress screen always covers entire display.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
- // Asking to layout into the overscan region, so give it that pure unrestricted
- // area.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
+ cf.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
} else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& (type == TYPE_STATUS_BAR
|| type == TYPE_TOAST
@@ -2105,11 +2033,9 @@ public class DisplayPolicy {
// ask for layout in only content. We can't currently figure out
// what the screen would be if only laying out to hide the nav bar.
cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
df.set(displayFrames.mUnrestricted);
pf.set(displayFrames.mUnrestricted);
} else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- of.set(displayFrames.mRestricted);
df.set(displayFrames.mRestricted);
pf.set(displayFrames.mRestricted);
@@ -2123,7 +2049,6 @@ public class DisplayPolicy {
}
} else {
cf.set(displayFrames.mRestricted);
- of.set(displayFrames.mRestricted);
df.set(displayFrames.mRestricted);
pf.set(displayFrames.mRestricted);
}
@@ -2140,7 +2065,7 @@ public class DisplayPolicy {
+ "): attached to " + attached);
// A child window should be placed inside of the same visible
// frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
+ setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
displayFrames);
} else {
if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
@@ -2152,28 +2077,23 @@ public class DisplayPolicy {
// top of the status bar. They are protected by the STATUS_BAR_SERVICE
// permission, so they have the same privileges as the status bar itself.
cf.set(displayFrames.mRestricted);
- of.set(displayFrames.mRestricted);
df.set(displayFrames.mRestricted);
pf.set(displayFrames.mRestricted);
} else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
// These dialogs are stable to interim decor changes.
cf.set(displayFrames.mStable);
- of.set(displayFrames.mStable);
df.set(displayFrames.mStable);
pf.set(displayFrames.mStable);
} else {
pf.set(displayFrames.mContent);
if (win.isVoiceInteraction()) {
cf.set(displayFrames.mVoiceContent);
- of.set(displayFrames.mVoiceContent);
df.set(displayFrames.mVoiceContent);
} else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
df.set(displayFrames.mDock);
} else {
cf.set(displayFrames.mContent);
- of.set(displayFrames.mContent);
df.set(displayFrames.mContent);
}
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
@@ -2252,34 +2172,8 @@ public class DisplayPolicy {
df.left = df.top = -10000;
df.right = df.bottom = 10000;
if (type != TYPE_WALLPAPER) {
- of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
- of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
- }
- }
-
- // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
- // need to provide information to the clients that want to pretend that you can draw there.
- // We only want to apply outsets to certain types of windows. For example, we never want to
- // apply the outsets to floating dialogs, because they wouldn't make sense there.
- final boolean useOutsets = shouldUseOutsets(attrs, fl);
- if (isDefaultDisplay && useOutsets) {
- final Rect osf = windowFrames.mOutsetFrame;
- osf.set(cf.left, cf.top, cf.right, cf.bottom);
- windowFrames.setHasOutsets(true);
- int outset = mWindowOutsetBottom;
- if (outset > 0) {
- int rotation = displayFrames.mRotation;
- if (rotation == Surface.ROTATION_0) {
- osf.bottom += outset;
- } else if (rotation == Surface.ROTATION_90) {
- osf.right += outset;
- } else if (rotation == Surface.ROTATION_180) {
- osf.top -= outset;
- } else if (rotation == Surface.ROTATION_270) {
- osf.left -= outset;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
- + " with rotation " + rotation + ", result: " + osf);
+ cf.left = cf.top = vf.left = vf.top = -10000;
+ cf.right = cf.bottom = vf.right = vf.bottom = 10000;
}
}
@@ -2288,11 +2182,9 @@ public class DisplayPolicy {
+ " attach=" + attached + " type=" + type
+ String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
- + " of=" + of.toShortString()
+ " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
+ " dcf=" + dcf.toShortString()
- + " sf=" + sf.toShortString()
- + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
+ + " sf=" + sf.toShortString());
if (!sTmpLastParentFrame.equals(pf)) {
windowFrames.setContentChanged(true);
@@ -2311,12 +2203,11 @@ public class DisplayPolicy {
}
}
- private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
- // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
+ private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
+ // The wallpaper has Real Ultimate Power
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
}
private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
@@ -2722,7 +2613,6 @@ public class DisplayPolicy {
- getNavigationBarFrameHeight(portraitRotation, uiMode);
updateConfigurationAndScreenSizeDependentBehaviors();
- mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
}
void updateConfigurationAndScreenSizeDependentBehaviors() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 67f1d1b217af..0c68084151c7 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -45,15 +45,19 @@ import android.database.ContentObserver;
import android.hardware.power.V1_0.PowerHint;
import android.net.Uri;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.IDisplayWindowRotationCallback;
import android.view.Surface;
+import android.view.WindowContainerTransaction;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
@@ -212,6 +216,31 @@ public class DisplayRotation {
private boolean mDemoHdmiRotationLock;
private boolean mDemoRotationLock;
+ private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
+
+ private boolean mIsWaitingForRemoteRotation = false;
+
+ private final Runnable mDisplayRotationHandlerTimeout =
+ new Runnable() {
+ @Override
+ public void run() {
+ continueRotation(mRotation, null /* transaction */);
+ }
+ };
+
+ private final IDisplayWindowRotationCallback mRemoteRotationCallback =
+ new IDisplayWindowRotationCallback.Stub() {
+ @Override
+ public void continueRotateDisplay(int targetRotation,
+ WindowContainerTransaction t) {
+ synchronized (mService.getWindowManagerLock()) {
+ mService.mH.sendMessage(PooledLambda.obtainMessage(
+ DisplayRotation::continueRotation, DisplayRotation.this,
+ targetRotation, t));
+ }
+ }
+ };
+
DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
this(service, displayContent, displayContent.getDisplayPolicy(),
service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
@@ -471,9 +500,52 @@ public class DisplayRotation {
prepareNormalRotationAnimation();
}
+ // The display is frozen now, give a remote handler (system ui) some time to reposition
+ // things.
+ startRemoteRotation(oldRotation, mRotation);
+
return true;
}
+ /**
+ * A Remote rotation is when we are waiting for some registered (remote)
+ * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
+ * to perform in sync with the rotation.
+ */
+ boolean isWaitingForRemoteRotation() {
+ return mIsWaitingForRemoteRotation;
+ }
+
+ private void startRemoteRotation(int fromRotation, int toRotation) {
+ if (mService.mDisplayRotationController == null) {
+ return;
+ }
+ mIsWaitingForRemoteRotation = true;
+ try {
+ mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
+ fromRotation, toRotation, mRemoteRotationCallback);
+ mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
+ mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
+ } catch (RemoteException e) {
+ mIsWaitingForRemoteRotation = false;
+ return;
+ }
+ }
+
+ private void continueRotation(int targetRotation, WindowContainerTransaction t) {
+ synchronized (mService.mGlobalLock) {
+ if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
+ // Drop it, this is either coming from an outdated remote rotation; or, we've
+ // already moved on.
+ return;
+ }
+ mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
+ mIsWaitingForRemoteRotation = false;
+ mService.mAtmService.applyContainerTransaction(t);
+ mDisplayContent.sendNewConfiguration();
+ }
+ }
+
void prepareNormalRotationAnimation() {
final RotationAnimationPair anim = selectRotationAnimation();
mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent);
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
new file mode 100644
index 000000000000..dbc452f6e026
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.IDisplayWindowListener;
+
+/**
+ * Manages dispatch of relevant hierarchy changes to interested listeners. Listeners are assumed
+ * to be remote.
+ */
+class DisplayWindowListenerController {
+ RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>();
+
+// private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>();
+ private final WindowManagerService mService;
+
+ DisplayWindowListenerController(WindowManagerService service) {
+ mService = service;
+ }
+
+ void registerListener(IDisplayWindowListener listener) {
+ synchronized (mService.mGlobalLock) {
+ mDisplayListeners.register(listener);
+ try {
+ for (int i = 0; i < mService.mAtmService.mRootActivityContainer.getChildCount();
+ ++i) {
+ ActivityDisplay d = mService.mAtmService.mRootActivityContainer.getChildAt(i);
+ listener.onDisplayAdded(d.mDisplayId);
+ }
+ } catch (RemoteException e) { }
+ }
+ }
+
+ void unregisterListener(IDisplayWindowListener listener) {
+ mDisplayListeners.unregister(listener);
+ }
+
+ void dispatchDisplayAdded(ActivityDisplay display) {
+ int count = mDisplayListeners.beginBroadcast();
+ for (int i = 0; i < count; ++i) {
+ try {
+ mDisplayListeners.getBroadcastItem(i).onDisplayAdded(display.mDisplayId);
+ } catch (RemoteException e) {
+ }
+ }
+ mDisplayListeners.finishBroadcast();
+ }
+
+ void dispatchDisplayRemoved(ActivityDisplay display) {
+ int count = mDisplayListeners.beginBroadcast();
+ for (int i = 0; i < count; ++i) {
+ try {
+ mDisplayListeners.getBroadcastItem(i).onDisplayRemoved(display.mDisplayId);
+ } catch (RemoteException e) {
+ }
+ }
+ mDisplayListeners.finishBroadcast();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 8507918df480..dac8b14c8ff1 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -100,10 +100,6 @@ class DisplayWindowSettings {
private static class Entry {
private final String mName;
- private int mOverscanLeft;
- private int mOverscanTop;
- private int mOverscanRight;
- private int mOverscanBottom;
private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
private int mUserRotation = Surface.ROTATION_0;
@@ -124,10 +120,6 @@ class DisplayWindowSettings {
private Entry(String name, Entry copyFrom) {
this(name);
- mOverscanLeft = copyFrom.mOverscanLeft;
- mOverscanTop = copyFrom.mOverscanTop;
- mOverscanRight = copyFrom.mOverscanRight;
- mOverscanBottom = copyFrom.mOverscanBottom;
mWindowingMode = copyFrom.mWindowingMode;
mUserRotationMode = copyFrom.mUserRotationMode;
mUserRotation = copyFrom.mUserRotation;
@@ -144,9 +136,7 @@ class DisplayWindowSettings {
/** @return {@code true} if all values are default. */
private boolean isEmpty() {
- return mOverscanLeft == 0 && mOverscanTop == 0 && mOverscanRight == 0
- && mOverscanBottom == 0
- && mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
&& mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
&& mUserRotation == Surface.ROTATION_0
&& mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
@@ -202,15 +192,6 @@ class DisplayWindowSettings {
return newEntry;
}
- void setOverscanLocked(DisplayInfo displayInfo, int left, int top, int right, int bottom) {
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mOverscanLeft = left;
- entry.mOverscanTop = top;
- entry.mOverscanRight = right;
- entry.mOverscanBottom = bottom;
- writeSettingsIfNeeded(entry, displayInfo);
- }
-
void setUserRotation(DisplayContent displayContent, int rotationMode, int rotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final Entry entry = getOrCreateEntry(displayInfo);
@@ -405,11 +386,6 @@ class DisplayWindowSettings {
// Setting windowing mode first, because it may override overscan values later.
dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId()));
- displayInfo.overscanLeft = entry.mOverscanLeft;
- displayInfo.overscanTop = entry.mOverscanTop;
- displayInfo.overscanRight = entry.mOverscanRight;
- displayInfo.overscanBottom = entry.mOverscanBottom;
-
dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
entry.mUserRotation, entry.mFixedToUserRotation);
@@ -536,10 +512,6 @@ class DisplayWindowSettings {
String name = parser.getAttributeValue(null, "name");
if (name != null) {
Entry entry = new Entry(name);
- entry.mOverscanLeft = getIntAttribute(parser, "overscanLeft");
- entry.mOverscanTop = getIntAttribute(parser, "overscanTop");
- entry.mOverscanRight = getIntAttribute(parser, "overscanRight");
- entry.mOverscanBottom = getIntAttribute(parser, "overscanBottom");
entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
WindowConfiguration.WINDOWING_MODE_UNDEFINED);
entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
@@ -602,18 +574,6 @@ class DisplayWindowSettings {
for (Entry entry : mEntries.values()) {
out.startTag(null, "display");
out.attribute(null, "name", entry.mName);
- if (entry.mOverscanLeft != 0) {
- out.attribute(null, "overscanLeft", Integer.toString(entry.mOverscanLeft));
- }
- if (entry.mOverscanTop != 0) {
- out.attribute(null, "overscanTop", Integer.toString(entry.mOverscanTop));
- }
- if (entry.mOverscanRight != 0) {
- out.attribute(null, "overscanRight", Integer.toString(entry.mOverscanRight));
- }
- if (entry.mOverscanBottom != 0) {
- out.attribute(null, "overscanBottom", Integer.toString(entry.mOverscanBottom));
- }
if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 6de48d1b2d07..03e13221c4a7 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -67,14 +67,14 @@ class LaunchParamsController {
/**
* Returns the {@link LaunchParams} calculated by the registered modifiers
- * @param task The {@link TaskRecord} currently being positioned.
+ * @param task The {@link Task} currently being positioned.
* @param layout The specified {@link WindowLayout}.
* @param activity The {@link ActivityRecord} currently being positioned.
* @param source The {@link ActivityRecord} from which activity was started from.
* @param options The {@link ActivityOptions} specified for the activity.
* @param result The resulting params.
*/
- void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ void calculate(Task task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, int phase, LaunchParams result) {
result.reset();
@@ -120,11 +120,11 @@ class LaunchParamsController {
* A convenience method for laying out a task.
* @return {@code true} if bounds were set on the task. {@code false} otherwise.
*/
- boolean layoutTask(TaskRecord task, WindowLayout layout) {
+ boolean layoutTask(Task task, WindowLayout layout) {
return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
}
- boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ boolean layoutTask(Task task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options) {
calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams);
@@ -184,7 +184,7 @@ class LaunchParamsController {
/** The bounds within the parent container. */
final Rect mBounds = new Rect();
- /** The id of the display the {@link TaskRecord} would prefer to be on. */
+ /** The id of the display the {@link Task} would prefer to be on. */
int mPreferredDisplayId;
/** The windowing mode to be in. */
@@ -304,7 +304,7 @@ class LaunchParamsController {
* @return see {@link LaunchParamsModifier.Result}
*/
@Result
- int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, @Phase int phase,
LaunchParams currentParams, LaunchParams outParams);
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 5d27390da588..c3bcc740a065 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -55,7 +55,7 @@ import java.util.function.IntFunction;
/**
* Persister that saves launch parameters in memory and in storage. It saves the last seen state of
* tasks key-ed on task's user ID and the activity used to launch the task ({@link
- * TaskRecord#realActivity}) and that's used to determine the launch params when the activity is
+ * Task#realActivity}) and that's used to determine the launch params when the activity is
* being launched again in {@link LaunchParamsController}.
*
* Need to hold {@link ActivityTaskManagerService#getGlobalLock()} to access this class.
@@ -196,7 +196,7 @@ class LaunchParamsPersister {
}
}
- void saveTask(TaskRecord task) {
+ void saveTask(Task task) {
final ComponentName name = task.realActivity;
final int userId = task.mUserId;
PersistableLaunchParams params;
@@ -220,7 +220,7 @@ class LaunchParamsPersister {
}
}
- private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
+ private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
final ActivityStack stack = task.getStack();
final int displayId = stack.mDisplayId;
final ActivityDisplay display =
@@ -245,7 +245,7 @@ class LaunchParamsPersister {
return changed;
}
- void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams outParams) {
+ void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) {
final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
final int userId = task != null ? task.mUserId : activity.mUserId;
@@ -412,7 +412,7 @@ class LaunchParamsPersister {
/** The bounds within the parent container. */
final Rect mBounds = new Rect();
- /** The unique id of the display the {@link TaskRecord} would prefer to be on. */
+ /** The unique id of the display the {@link Task} would prefer to be on. */
String mDisplayUniqueId;
/** The windowing mode to be in. */
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index dc45686a1359..6810f8c16164 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -32,11 +32,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTAS
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -157,7 +157,7 @@ public class LockTaskController {
*
* The list is empty if LockTask is inactive.
*/
- private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
+ private final ArrayList<Task> mLockTaskModeTasks = new ArrayList<>();
/**
* Packages that are allowed to be launched into the lock task mode for each user.
@@ -221,14 +221,14 @@ public class LockTaskController {
* back of the stack.
*/
@VisibleForTesting
- boolean isTaskLocked(TaskRecord task) {
+ boolean isTaskLocked(Task task) {
return mLockTaskModeTasks.contains(task);
}
/**
* @return {@code true} whether this task first started the current LockTask session.
*/
- private boolean isRootTask(TaskRecord task) {
+ private boolean isRootTask(Task task) {
return mLockTaskModeTasks.indexOf(task) == 0;
}
@@ -237,7 +237,7 @@ public class LockTaskController {
* of the last locked task and finishing it would mean that lock task mode is ended illegally.
*/
boolean activityBlockedFromFinish(ActivityRecord activity) {
- final TaskRecord task = activity.getTaskRecord();
+ final Task task = activity.getTask();
if (activity == task.getRootActivity()
&& activity == task.getTopActivity()
&& task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
@@ -254,7 +254,7 @@ public class LockTaskController {
* {@link ActivityStack#moveTaskToBackLocked(int)}
* @see #mLockTaskModeTasks
*/
- boolean canMoveTaskToBack(TaskRecord task) {
+ boolean canMoveTaskToBack(Task task) {
if (isRootTask(task)) {
showLockTaskToast();
return false;
@@ -266,7 +266,7 @@ public class LockTaskController {
* @return whether the requested task is allowed to be locked (either whitelisted, or declares
* lockTaskMode="always" in the manifest).
*/
- boolean isTaskWhitelisted(TaskRecord task) {
+ boolean isTaskWhitelisted(Task task) {
switch(task.mLockTaskAuth) {
case LOCK_TASK_AUTH_WHITELISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
@@ -282,7 +282,7 @@ public class LockTaskController {
/**
* @return whether the requested task is disallowed to be launched.
*/
- boolean isLockTaskModeViolation(TaskRecord task) {
+ boolean isLockTaskModeViolation(Task task) {
return isLockTaskModeViolation(task, false);
}
@@ -290,7 +290,7 @@ public class LockTaskController {
* @param isNewClearTask whether the task would be cleared as part of the operation.
* @return whether the requested task is disallowed to be launched.
*/
- boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
+ boolean isLockTaskModeViolation(Task task, boolean isNewClearTask) {
if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
showLockTaskToast();
return true;
@@ -301,14 +301,14 @@ public class LockTaskController {
/**
* @return the root task of the lock task.
*/
- TaskRecord getRootTask() {
+ Task getRootTask() {
if (mLockTaskModeTasks.isEmpty()) {
return null;
}
return mLockTaskModeTasks.get(0);
}
- private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
+ private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
// TODO: Double check what's going on here. If the task is already in lock task mode, it's
// likely whitelisted, so will return false below.
if (isTaskLocked(task) && !isNewClearTask) {
@@ -339,7 +339,7 @@ public class LockTaskController {
& DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0;
}
- private boolean isEmergencyCallTask(TaskRecord task) {
+ private boolean isEmergencyCallTask(Task task) {
final Intent intent = task.intent;
if (intent == null) {
return false;
@@ -384,7 +384,7 @@ public class LockTaskController {
* @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
* they differ from the one that launched lock task mode.
*/
- void stopLockTaskMode(@Nullable TaskRecord task, boolean isSystemCaller, int callingUid) {
+ void stopLockTaskMode(@Nullable Task task, boolean isSystemCaller, int callingUid) {
if (mLockTaskModeState == LOCK_TASK_MODE_NONE) {
return;
}
@@ -407,8 +407,8 @@ public class LockTaskController {
// It is possible lockTaskMode was started by the system process because
// android:lockTaskMode is set to a locking value in the application manifest
// instead of the app calling startLockTaskMode. In this case
- // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
- // {@link TaskRecord.effectiveUid} instead. Also caller with
+ // {@link Task.mLockTaskUid} will be 0, so we compare the callingUid to the
+ // {@link Task.effectiveUid} instead. Also caller with
// {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
if (callingUid != task.mLockTaskUid
&& (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) {
@@ -425,7 +425,7 @@ public class LockTaskController {
* Clear all locked tasks and request the end of LockTask mode.
*
* This method is called by UserController when starting a new foreground user, and,
- * unlike {@link #stopLockTaskMode(TaskRecord, boolean, int)}, it doesn't perform the checks.
+ * unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
*/
void clearLockedTasks(String reason) {
if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
@@ -443,7 +443,7 @@ public class LockTaskController {
*
* @param task the task to be cleared from LockTask mode.
*/
- void clearLockedTask(final TaskRecord task) {
+ void clearLockedTask(final Task task) {
if (task == null || mLockTaskModeTasks.isEmpty()) return;
if (task == mLockTaskModeTasks.get(0)) {
@@ -466,7 +466,7 @@ public class LockTaskController {
* Remove the given task from the locked task list. If this was the last task in the list,
* lock task mode is stopped.
*/
- private void removeLockedTask(final TaskRecord task) {
+ private void removeLockedTask(final Task task) {
if (!mLockTaskModeTasks.remove(task)) {
return;
}
@@ -527,7 +527,7 @@ public class LockTaskController {
* at the calling task's mLockTaskAuth to decide which mode to start.
* @param callingUid the caller that requested the launch of lock task mode.
*/
- void startLockTaskMode(@NonNull TaskRecord task, boolean isSystemCaller, int callingUid) {
+ void startLockTaskMode(@NonNull Task task, boolean isSystemCaller, int callingUid) {
if (!isSystemCaller) {
task.mLockTaskUid = callingUid;
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
@@ -555,7 +555,7 @@ public class LockTaskController {
* @param lockTaskModeState whether fully locked or pinned mode.
* @param andResume whether the task should be brought to foreground as part of the operation.
*/
- private void setLockTaskMode(@NonNull TaskRecord task, int lockTaskModeState,
+ private void setLockTaskMode(@NonNull Task task, int lockTaskModeState,
String reason, boolean andResume) {
// Should have already been checked, but do it again.
if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
@@ -632,7 +632,7 @@ public class LockTaskController {
boolean taskChanged = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
+ final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
lockedTask.setLockTaskAuth();
@@ -659,7 +659,7 @@ public class LockTaskController {
}
final ActivityRecord r = mSupervisor.mRootActivityContainer.topRunningActivity();
- final TaskRecord task = (r != null) ? r.getTaskRecord() : null;
+ final Task task = (r != null) ? r.getTask() : null;
if (mLockTaskModeTasks.isEmpty() && task!= null
&& task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
// This task must have just been authorized.
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 71696778f891..2f46937bb1d9 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -119,7 +119,7 @@ class RecentTasks {
private static final long FREEZE_TASK_LIST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
// Comparator to sort by taskId
- private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
+ private static final Comparator<Task> TASK_ID_COMPARATOR =
(lhs, rhs) -> rhs.mTaskId - lhs.mTaskId;
// Placeholder variables to keep track of activities/apps that are no longer avialble while
@@ -135,12 +135,12 @@ class RecentTasks {
/**
* Called when a task is added to the recent tasks list.
*/
- void onRecentTaskAdded(TaskRecord task);
+ void onRecentTaskAdded(Task task);
/**
* Called when a task is removed from the recent tasks list.
*/
- void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess);
+ void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess);
}
/**
@@ -171,7 +171,7 @@ class RecentTasks {
DEFAULT_INITIAL_CAPACITY);
// List of all active recent tasks
- private final ArrayList<TaskRecord> mTasks = new ArrayList<>();
+ private final ArrayList<Task> mTasks = new ArrayList<>();
private final ArrayList<Callbacks> mCallbacks = new ArrayList<>();
// These values are generally loaded from resources, but can be set dynamically in the tests
@@ -188,7 +188,7 @@ class RecentTasks {
private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS;
// Mainly to avoid object recreation on multiple calls.
- private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
+ private final ArrayList<Task> mTmpRecents = new ArrayList<>();
private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
@@ -211,7 +211,7 @@ class RecentTasks {
final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
if (dc.pointWithinAppWindow(x, y)) {
final ActivityStack stack = mService.getTopDisplayFocusedStack();
- final TaskRecord topTask = stack != null ? stack.topTask() : null;
+ final Task topTask = stack != null ? stack.topTask() : null;
resetFreezeTaskListReordering(topTask);
}
}
@@ -288,7 +288,7 @@ class RecentTasks {
* Commits the frozen recent task list order, moving the provided {@param topTask} to the
* front of the list.
*/
- void resetFreezeTaskListReordering(TaskRecord topTask) {
+ void resetFreezeTaskListReordering(Task topTask) {
if (!mFreezeTaskListReordering) {
return;
}
@@ -319,9 +319,7 @@ class RecentTasks {
void resetFreezeTaskListReorderingOnTimeout() {
synchronized (mService.mGlobalLock) {
final ActivityStack focusedStack = mService.getTopDisplayFocusedStack();
- final TaskRecord topTask = focusedStack != null
- ? focusedStack.topTask()
- : null;
+ final Task topTask = focusedStack != null ? focusedStack.topTask() : null;
resetFreezeTaskListReordering(topTask);
}
}
@@ -432,14 +430,14 @@ class RecentTasks {
mCallbacks.remove(callback);
}
- private void notifyTaskAdded(TaskRecord task) {
+ private void notifyTaskAdded(Task task) {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onRecentTaskAdded(task);
}
mTaskNotificationController.notifyTaskListUpdated();
}
- private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+ private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
}
@@ -463,14 +461,14 @@ class RecentTasks {
// Check if any tasks are added before recents is loaded
final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
- for (final TaskRecord task : mTasks) {
+ for (final Task task : mTasks) {
if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
preaddedTasks.put(task.mTaskId, true);
}
}
Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
- List<TaskRecord> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+ List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
mTasks.addAll(tasks);
cleanupLocked(userId);
mUsersWithRecentsLoaded.put(userId, true);
@@ -509,7 +507,7 @@ class RecentTasks {
/**
* Kicks off the task persister to write any pending tasks to disk.
*/
- void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+ void notifyTaskPersisterLocked(Task task, boolean flush) {
final ActivityStack stack = task != null ? task.getStack() : null;
if (stack != null && stack.isHomeOrRecentsStack()) {
// Never persist the home or recents stack.
@@ -529,7 +527,7 @@ class RecentTasks {
}
}
for (int i = mTasks.size() - 1; i >= 0; i--) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
if (shouldPersistTaskLocked(task)) {
// Set of persisted taskIds for task.userId should not be null here
// TODO Investigate why it can happen. For now initialize with an empty set
@@ -543,7 +541,7 @@ class RecentTasks {
}
}
- private static boolean shouldPersistTaskLocked(TaskRecord task) {
+ private static boolean shouldPersistTaskLocked(Task task) {
final ActivityStack stack = task.getStack();
return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack());
}
@@ -613,11 +611,11 @@ class RecentTasks {
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
- TaskRecord tr = mTasks.get(i);
- if (tr.mUserId == userId) {
+ Task task = mTasks.get(i);
+ if (task.mUserId == userId) {
if(DEBUG_TASKS) Slog.i(TAG_TASKS,
- "remove RecentTask " + tr + " when finishing user" + userId);
- remove(tr);
+ "remove RecentTask " + task + " when finishing user" + userId);
+ remove(task);
}
}
}
@@ -625,17 +623,17 @@ class RecentTasks {
void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
final Set<String> packageNames = Sets.newHashSet(packages);
for (int i = mTasks.size() - 1; i >= 0; --i) {
- final TaskRecord tr = mTasks.get(i);
- if (tr.realActivity != null
- && packageNames.contains(tr.realActivity.getPackageName())
- && tr.mUserId == userId
- && tr.realActivitySuspended != suspended) {
- tr.realActivitySuspended = suspended;
+ final Task task = mTasks.get(i);
+ if (task.realActivity != null
+ && packageNames.contains(task.realActivity.getPackageName())
+ && task.mUserId == userId
+ && task.realActivitySuspended != suspended) {
+ task.realActivitySuspended = suspended;
if (suspended) {
- mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
+ mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
REMOVE_FROM_RECENTS, "suspended-package");
}
- notifyTaskPersisterLocked(tr, false);
+ notifyTaskPersisterLocked(task, false);
}
}
}
@@ -645,22 +643,22 @@ class RecentTasks {
return;
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
- final TaskRecord tr = mTasks.get(i);
- if (tr.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(tr)) {
- remove(tr);
+ final Task task = mTasks.get(i);
+ if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+ remove(task);
}
}
}
void removeTasksByPackageName(String packageName, int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
- final TaskRecord tr = mTasks.get(i);
+ final Task task = mTasks.get(i);
final String taskPackageName =
- tr.getBaseIntent().getComponent().getPackageName();
- if (tr.mUserId != userId) continue;
+ task.getBaseIntent().getComponent().getPackageName();
+ if (task.mUserId != userId) continue;
if (!taskPackageName.equals(packageName)) continue;
- mSupervisor.removeTaskByIdLocked(tr.mTaskId, true, REMOVE_FROM_RECENTS,
+ mSupervisor.removeTaskByIdLocked(task.mTaskId, true, REMOVE_FROM_RECENTS,
"remove-package-task");
}
}
@@ -668,11 +666,11 @@ class RecentTasks {
void removeAllVisibleTasks(int userId) {
Set<Integer> profileIds = getProfileIds(userId);
for (int i = mTasks.size() - 1; i >= 0; --i) {
- final TaskRecord tr = mTasks.get(i);
- if (!profileIds.contains(tr.mUserId)) continue;
- if (isVisibleRecentTask(tr)) {
+ final Task task = mTasks.get(i);
+ if (!profileIds.contains(task.mUserId)) continue;
+ if (isVisibleRecentTask(task)) {
mTasks.remove(i);
- notifyTaskRemoved(tr, true /* wasTrimmed */, true /* killProcess */);
+ notifyTaskRemoved(task, true /* wasTrimmed */, true /* killProcess */);
}
}
}
@@ -680,16 +678,16 @@ class RecentTasks {
void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
- final TaskRecord tr = mTasks.get(i);
- if (userId != UserHandle.USER_ALL && tr.mUserId != userId) {
+ final Task task = mTasks.get(i);
+ if (userId != UserHandle.USER_ALL && task.mUserId != userId) {
continue;
}
- ComponentName cn = tr.intent != null ? tr.intent.getComponent() : null;
+ ComponentName cn = task.intent != null ? task.intent.getComponent() : null;
final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
&& (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
if (sameComponent) {
- mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
+ mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
REMOVE_FROM_RECENTS, "disabled-package");
}
}
@@ -714,7 +712,7 @@ class RecentTasks {
final IPackageManager pm = AppGlobals.getPackageManager();
for (int i = recentsCount - 1; i >= 0; i--) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
if (userId != UserHandle.USER_ALL && task.mUserId != userId) {
// Only look at tasks for the user ID of interest.
continue;
@@ -810,7 +808,7 @@ class RecentTasks {
* @return whether the given {@param task} can be added to the list without causing another
* task to be trimmed as a result of that add.
*/
- private boolean canAddTaskWithoutTrim(TaskRecord task) {
+ private boolean canAddTaskWithoutTrim(Task task) {
return findRemoveIndexForAddTask(task) == -1;
}
@@ -821,18 +819,18 @@ class RecentTasks {
final ArrayList<IBinder> list = new ArrayList<>();
final int size = mTasks.size();
for (int i = 0; i < size; i++) {
- final TaskRecord tr = mTasks.get(i);
+ final Task task = mTasks.get(i);
// Skip tasks that do not match the caller. We don't need to verify
// callingPackage, because we are also limiting to callingUid and know
// that will limit to the correct security sandbox.
- if (tr.effectiveUid != callingUid) {
+ if (task.effectiveUid != callingUid) {
continue;
}
- Intent intent = tr.getBaseIntent();
+ Intent intent = task.getBaseIntent();
if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
continue;
}
- AppTaskImpl taskImpl = new AppTaskImpl(mService, tr.mTaskId, callingUid);
+ AppTaskImpl taskImpl = new AppTaskImpl(mService, task.mTaskId, callingUid);
list.add(taskImpl.asBinder());
}
return list;
@@ -893,11 +891,11 @@ class RecentTasks {
final int size = mTasks.size();
int numVisibleTasks = 0;
for (int i = 0; i < size; i++) {
- final TaskRecord tr = mTasks.get(i);
+ final Task task = mTasks.get(i);
- if (isVisibleRecentTask(tr)) {
+ if (isVisibleRecentTask(task)) {
numVisibleTasks++;
- if (isInVisibleRange(tr, i, numVisibleTasks, withExcluded)) {
+ if (isInVisibleRange(task, i, numVisibleTasks, withExcluded)) {
// Fall through
} else {
// Not in visible range
@@ -914,48 +912,48 @@ class RecentTasks {
}
// Only add calling user or related users recent tasks
- if (!includedUsers.contains(Integer.valueOf(tr.mUserId))) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
+ if (!includedUsers.contains(Integer.valueOf(task.mUserId))) {
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + task);
continue;
}
- if (tr.realActivitySuspended) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
+ if (task.realActivitySuspended) {
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + task);
continue;
}
if (!getTasksAllowed) {
// If the caller doesn't have the GET_TASKS permission, then only
// allow them to see a small subset of tasks -- their own and home.
- if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
+ if (!task.isActivityTypeHome() && task.effectiveUid != callingUid) {
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + task);
continue;
}
}
- if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
+ if (task.autoRemoveRecents && task.getTopActivity() == null) {
// Don't include auto remove tasks that are finished or finishing.
if (DEBUG_RECENTS) {
- Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + tr);
+ Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + task);
}
continue;
}
- if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
+ if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !task.isAvailable) {
if (DEBUG_RECENTS) {
- Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + tr);
+ Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + task);
}
continue;
}
- if (!tr.mUserSetupComplete) {
+ if (!task.mUserSetupComplete) {
// Don't include task launched while user is not done setting-up.
if (DEBUG_RECENTS) {
- Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + tr);
+ Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + task);
}
continue;
}
- final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
+ final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(task);
if (!getDetailedTasks) {
rti.baseIntent.replaceExtras((Bundle) null);
}
@@ -971,7 +969,7 @@ class RecentTasks {
void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) {
final int size = mTasks.size();
for (int i = 0; i < size; i++) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
+ " persistable=" + task.isPersistable);
final ActivityStack stack = task.getStack();
@@ -987,7 +985,7 @@ class RecentTasks {
}
@VisibleForTesting
- ArrayList<TaskRecord> getRawTasks() {
+ ArrayList<Task> getRawTasks() {
return mTasks;
}
@@ -999,11 +997,11 @@ class RecentTasks {
final int size = mTasks.size();
int numVisibleTasks = 0;
for (int i = 0; i < size; i++) {
- final TaskRecord tr = mTasks.get(i);
- if (isVisibleRecentTask(tr)) {
+ final Task task = mTasks.get(i);
+ if (isVisibleRecentTask(task)) {
numVisibleTasks++;
- if (isInVisibleRange(tr, i, numVisibleTasks, false /* skipExcludedCheck */)) {
- res.put(tr.mTaskId, true);
+ if (isInVisibleRange(task, i, numVisibleTasks, false /* skipExcludedCheck */)) {
+ res.put(task.mTaskId, true);
}
}
}
@@ -1013,12 +1011,12 @@ class RecentTasks {
/**
* @return the task in the task list with the given {@param id} if one exists.
*/
- TaskRecord getTask(int id) {
+ Task getTask(int id) {
final int recentsCount = mTasks.size();
for (int i = 0; i < recentsCount; i++) {
- TaskRecord tr = mTasks.get(i);
- if (tr.mTaskId == id) {
- return tr;
+ Task task = mTasks.get(i);
+ if (task.mTaskId == id) {
+ return task;
}
}
return null;
@@ -1027,7 +1025,7 @@ class RecentTasks {
/**
* Add a new task to the recent tasks list.
*/
- void add(TaskRecord task) {
+ void add(Task task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
@@ -1098,7 +1096,7 @@ class RecentTasks {
} else if (isAffiliated) {
// If this is a new affiliated task, then move all of the affiliated tasks
// to the front and insert this new one.
- TaskRecord other = task.mNextAffiliate;
+ Task other = task.mNextAffiliate;
if (other == null) {
other = task.mPrevAffiliate;
}
@@ -1154,7 +1152,7 @@ class RecentTasks {
/**
* Add the task to the bottom if possible.
*/
- boolean addToBottom(TaskRecord task) {
+ boolean addToBottom(Task task) {
if (!canAddTaskWithoutTrim(task)) {
// Adding this task would cause the task to be removed (since it's appended at
// the bottom and would be trimmed) so just return now
@@ -1168,7 +1166,7 @@ class RecentTasks {
/**
* Remove a task from the recent tasks list.
*/
- void remove(TaskRecord task) {
+ void remove(Task task) {
mTasks.remove(task);
notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
}
@@ -1186,10 +1184,10 @@ class RecentTasks {
// Remove from the end of the list until we reach the max number of recents
while (recentsCount > mGlobalMaxNumTasks) {
- final TaskRecord tr = mTasks.remove(recentsCount - 1);
- notifyTaskRemoved(tr, true /* wasTrimmed */, false /* killProcess */);
+ final Task task = mTasks.remove(recentsCount - 1);
+ notifyTaskRemoved(task, true /* wasTrimmed */, false /* killProcess */);
recentsCount--;
- if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr
+ if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + task
+ " max=" + mGlobalMaxNumTasks);
}
@@ -1208,7 +1206,7 @@ class RecentTasks {
// Remove any inactive tasks, calculate the latest set of visible tasks.
int numVisibleTasks = 0;
for (int i = 0; i < mTasks.size();) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
if (!mHasVisibleRecentTasks) {
@@ -1250,7 +1248,7 @@ class RecentTasks {
/**
* @return whether the given task should be considered active.
*/
- private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) {
+ private boolean isActiveRecentTask(Task task, SparseBooleanArray quietProfileUserIds) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
+ " globalMax=" + mGlobalMaxNumTasks);
@@ -1262,7 +1260,7 @@ class RecentTasks {
if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.mTaskId) {
// Keep the task active if its affiliated task is also active
- final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId);
+ final Task affiliatedTask = getTask(task.mAffiliatedTaskId);
if (affiliatedTask != null) {
if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
@@ -1280,7 +1278,7 @@ class RecentTasks {
* @return whether the given active task should be presented to the user through SystemUI.
*/
@VisibleForTesting
- boolean isVisibleRecentTask(TaskRecord task) {
+ boolean isVisibleRecentTask(Task task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
+ " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
+ " sessionDuration=" + mActiveTasksSessionDurationMs
@@ -1338,7 +1336,7 @@ class RecentTasks {
/**
* @return whether the given visible task is within the policy range.
*/
- private boolean isInVisibleRange(TaskRecord task, int taskIndex, int numVisibleTasks,
+ private boolean isInVisibleRange(Task task, int taskIndex, int numVisibleTasks,
boolean skipExcludedCheck) {
if (!skipExcludedCheck) {
// Keep the most recent task even if it is excluded from recents
@@ -1376,7 +1374,7 @@ class RecentTasks {
/**
* @return whether the given task can be trimmed even if it is outside the visible range.
*/
- protected boolean isTrimmable(TaskRecord task) {
+ protected boolean isTrimmable(Task task) {
final ActivityStack stack = task.getStack();
// No stack for task, just trim it
@@ -1399,7 +1397,7 @@ class RecentTasks {
* If needed, remove oldest existing entries in recents that are for the same kind
* of task as the given one.
*/
- private void removeForAddTask(TaskRecord task) {
+ private void removeForAddTask(Task task) {
final int removeIndex = findRemoveIndexForAddTask(task);
if (removeIndex == -1) {
// Nothing to trim
@@ -1409,7 +1407,7 @@ class RecentTasks {
// There is a similar task that will be removed for the addition of {@param task}, but it
// can be the same task, and if so, the task will be re-added in add(), so skip the
// callbacks here.
- final TaskRecord removedTask = mTasks.remove(removeIndex);
+ final Task removedTask = mTasks.remove(removeIndex);
if (removedTask != task) {
notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
@@ -1422,7 +1420,7 @@ class RecentTasks {
* Find the task that would be removed if the given {@param task} is added to the recent tasks
* list (if any).
*/
- private int findRemoveIndexForAddTask(TaskRecord task) {
+ private int findRemoveIndexForAddTask(Task task) {
if (mFreezeTaskListReordering) {
// Defer removing tasks due to the addition of new tasks until the task list is unfrozen
return -1;
@@ -1433,15 +1431,15 @@ class RecentTasks {
final boolean document = intent != null && intent.isDocument();
int maxRecents = task.maxRecents - 1;
for (int i = 0; i < recentsCount; i++) {
- final TaskRecord tr = mTasks.get(i);
- if (task != tr) {
- if (!hasCompatibleActivityTypeAndWindowingMode(task, tr)
- || task.mUserId != tr.mUserId) {
+ final Task t = mTasks.get(i);
+ if (task != t) {
+ if (!hasCompatibleActivityTypeAndWindowingMode(task, t)
+ || task.mUserId != t.mUserId) {
continue;
}
- final Intent trIntent = tr.intent;
+ final Intent trIntent = t.intent;
final boolean sameAffinity =
- task.affinity != null && task.affinity.equals(tr.affinity);
+ task.affinity != null && task.affinity.equals(t.affinity);
final boolean sameIntent = intent != null && intent.filterEquals(trIntent);
boolean multiTasksAllowed = false;
final int flags = intent.getFlags();
@@ -1458,8 +1456,8 @@ class RecentTasks {
if (bothDocuments) {
// Do these documents belong to the same activity?
final boolean sameActivity = task.realActivity != null
- && tr.realActivity != null
- && task.realActivity.equals(tr.realActivity);
+ && t.realActivity != null
+ && task.realActivity.equals(t.realActivity);
if (!sameActivity) {
// If the document is open in another app or is not the same document, we
// don't need to trim it.
@@ -1487,7 +1485,7 @@ class RecentTasks {
// Extract the affiliates of the chain containing recent at index start.
private int processNextAffiliateChainLocked(int start) {
- final TaskRecord startTask = mTasks.get(start);
+ final Task startTask = mTasks.get(start);
final int affiliateId = startTask.mAffiliatedTaskId;
// Quick identification of isolated tasks. I.e. those not launched behind.
@@ -1503,7 +1501,7 @@ class RecentTasks {
// Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
mTmpRecents.clear();
for (int i = mTasks.size() - 1; i >= start; --i) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
if (task.mAffiliatedTaskId == affiliateId) {
mTasks.remove(i);
mTmpRecents.add(task);
@@ -1516,7 +1514,7 @@ class RecentTasks {
// Go through and fix up the linked list.
// The first one is the end of the chain and has no next.
- final TaskRecord first = mTmpRecents.get(0);
+ final Task first = mTmpRecents.get(0);
first.inRecents = true;
if (first.mNextAffiliate != null) {
Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
@@ -1526,8 +1524,8 @@ class RecentTasks {
// Everything in the middle is doubly linked from next to prev.
final int tmpSize = mTmpRecents.size();
for (int i = 0; i < tmpSize - 1; ++i) {
- final TaskRecord next = mTmpRecents.get(i);
- final TaskRecord prev = mTmpRecents.get(i + 1);
+ final Task next = mTmpRecents.get(i);
+ final Task prev = mTmpRecents.get(i + 1);
if (next.mPrevAffiliate != prev) {
Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
" setting prev=" + prev);
@@ -1543,7 +1541,7 @@ class RecentTasks {
prev.inRecents = true;
}
// The last one is the beginning of the list and has no prev.
- final TaskRecord last = mTmpRecents.get(tmpSize - 1);
+ final Task last = mTmpRecents.get(tmpSize - 1);
if (last.mPrevAffiliate != null) {
Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
last.setPrevAffiliate(null);
@@ -1558,9 +1556,9 @@ class RecentTasks {
return start + tmpSize;
}
- private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
+ private boolean moveAffiliatedTasksToFront(Task task, int taskIndex) {
int recentsCount = mTasks.size();
- TaskRecord top = task;
+ Task top = task;
int topIndex = taskIndex;
while (top.mNextAffiliate != null && topIndex > 0) {
top = top.mNextAffiliate;
@@ -1571,9 +1569,9 @@ class RecentTasks {
// Find the end of the chain, doing a sanity check along the way.
boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
int endIndex = topIndex;
- TaskRecord prev = top;
+ Task prev = top;
while (endIndex < recentsCount) {
- TaskRecord cur = mTasks.get(endIndex);
+ Task cur = mTasks.get(endIndex);
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
+ endIndex + " " + cur);
if (cur == top) {
@@ -1648,7 +1646,7 @@ class RecentTasks {
for (int i=topIndex; i<=endIndex; i++) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
+ " from " + i + " to " + (i-topIndex));
- TaskRecord cur = mTasks.remove(i);
+ Task cur = mTasks.remove(i);
mTasks.add(i - topIndex, cur);
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex
@@ -1676,9 +1674,9 @@ class RecentTasks {
boolean printedHeader = false;
final int size = mTasks.size();
for (int i = 0; i < size; i++) {
- final TaskRecord tr = mTasks.get(i);
- if (dumpPackage != null && (tr.realActivity == null ||
- !dumpPackage.equals(tr.realActivity.getPackageName()))) {
+ final Task task = mTasks.get(i);
+ if (dumpPackage != null && (task.realActivity == null ||
+ !dumpPackage.equals(task.realActivity.getPackageName()))) {
continue;
}
@@ -1688,9 +1686,9 @@ class RecentTasks {
printedAnything = true;
}
pw.print(" * Recent #"); pw.print(i); pw.print(": ");
- pw.println(tr);
+ pw.println(task);
if (dumpAll) {
- tr.dump(pw, " ");
+ task.dump(pw, " ");
}
}
@@ -1724,9 +1722,9 @@ class RecentTasks {
}
/**
- * Creates a new RecentTaskInfo from a TaskRecord.
+ * Creates a new RecentTaskInfo from a Task.
*/
- ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
+ ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr) {
ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
tr.fillTaskInfo(rti);
// Fill in some deprecated values
@@ -1740,7 +1738,7 @@ class RecentTasks {
* compatible. This is necessary because we currently don't persist the activity type
* or the windowing mode with the task, so they can be undefined when restored.
*/
- private boolean hasCompatibleActivityTypeAndWindowingMode(TaskRecord t1, TaskRecord t2) {
+ private boolean hasCompatibleActivityTypeAndWindowingMode(Task t1, Task t2) {
final int activityType = t1.getActivityType();
final int windowingMode = t1.getWindowingMode();
final boolean isUndefinedType = activityType == ACTIVITY_TYPE_UNDEFINED;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 83804a767d0b..fc74d00e82db 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -107,7 +107,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack);
if (targetActivity != null) {
- if (targetActivity.visible || targetActivity.isTopRunningActivity()) {
+ if (targetActivity.mVisibleRequested || targetActivity.isTopRunningActivity()) {
// The activity is ready.
return;
}
@@ -189,7 +189,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// Send launch hint if we are actually launching the target. If it's already visible
// (shouldn't happen in general) we don't need to send it.
- if (targetActivity == null || !targetActivity.visible) {
+ if (targetActivity == null || !targetActivity.mVisibleRequested) {
mService.mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
true /* forceSend */, targetActivity);
}
@@ -211,7 +211,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// If there are multiple tasks in the target stack (ie. the home stack, with 3p
// and default launchers coexisting), then move the task to the top as a part of
// moving the stack to the front
- final TaskRecord task = targetActivity.getTaskRecord();
+ final Task task = targetActivity.getTask();
if (targetStack.topTask() != task) {
targetStack.positionChildAtTop(task);
}
@@ -328,7 +328,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
if (sendUserLeaveHint) {
// Setting this allows the previous app to PiP.
mStackSupervisor.mUserLeaving = true;
- targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
+ targetStack.moveTaskToFrontLocked(targetActivity.getTask(),
true /* noAnimation */, null /* activityOptions */,
targetActivity.appTimeTracker,
"RecentsAnimation.onAnimationFinished()");
@@ -491,7 +491,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
- final TaskRecord task = targetStack.getChildAt(i);
+ final Task task = targetStack.getChildAt(i);
if (task.mUserId == mUserId
&& task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
return task.getTopActivity();
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index e60cd933d4b8..5a21016e54dc 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -62,8 +62,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import static java.lang.Integer.MAX_VALUE;
@@ -858,7 +858,7 @@ class RootActivityContainer extends ConfigurationContainer
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
stack.switchUser(userId);
- TaskRecord task = stack.topTask();
+ Task task = stack.topTask();
if (task != null) {
stack.positionChildAtTop(task);
}
@@ -966,7 +966,7 @@ class RootActivityContainer extends ConfigurationContainer
final ActivityDisplay display = r.getActivityStack().getDisplay();
try {
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
final ActivityStack pinnedStack = display.getPinnedStack();
// This will change the pinned stack's windowing mode to its original mode, ensuring
@@ -995,7 +995,7 @@ class RootActivityContainer extends ConfigurationContainer
// activity into that task, and then reparent the whole task to the new stack. This
// ensures that all the necessary work to migrate states in the old and new stacks
// is also done.
- final TaskRecord newTask = task.getStack().createTaskRecord(
+ final Task newTask = task.getStack().createTask(
mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), r.info,
r.intent, null, null, true);
r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
@@ -1090,7 +1090,7 @@ class RootActivityContainer extends ConfigurationContainer
* @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
int finishTopCrashedActivities(WindowProcessController app, String reason) {
- TaskRecord finishedTask = null;
+ Task finishedTask = null;
ActivityStack focusedStack = getTopDisplayFocusedStack();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
@@ -1098,7 +1098,7 @@ class RootActivityContainer extends ConfigurationContainer
// so we need to be careful with indexes in the loop and check child count every time.
for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason);
+ final Task t = stack.finishTopCrashedActivityLocked(app, reason);
if (stack == focusedStack || finishedTask == null) {
finishedTask = t;
}
@@ -1156,6 +1156,9 @@ class RootActivityContainer extends ConfigurationContainer
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+ } else if (targetStack == null && !display.hasChild()) {
+ result |= resumeHomeActivity(null /* prev */, "empty-display",
+ display.mDisplayId);
}
}
}
@@ -1253,14 +1256,14 @@ class RootActivityContainer extends ConfigurationContainer
info.position = display != null ? display.getIndexOf(stack) : 0;
info.configuration.setTo(stack.getConfiguration());
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ ArrayList<Task> tasks = stack.getAllTasks();
final int numTasks = tasks.size();
int[] taskIds = new int[numTasks];
String[] taskNames = new String[numTasks];
Rect[] taskBounds = new Rect[numTasks];
int[] taskUserIds = new int[numTasks];
for (int i = 0; i < numTasks; ++i) {
- final TaskRecord task = tasks.get(i);
+ final Task task = tasks.get(i);
taskIds[i] = task.mTaskId;
taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
: task.realActivity != null ? task.realActivity.flattenToString()
@@ -1547,7 +1550,7 @@ class RootActivityContainer extends ConfigurationContainer
void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
// Tasks is non-null only if two or more tasks are found.
- ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks();
+ ArraySet<Task> tasks = app.getReleaseSomeActivitiesTasks();
if (tasks == null) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
return;
@@ -1630,7 +1633,7 @@ class RootActivityContainer extends ConfigurationContainer
}
ActivityStack getLaunchStack(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) {
+ @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) {
return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */,
-1 /* no realCallingPid */, -1 /* no realCallingUid */);
}
@@ -1648,7 +1651,7 @@ class RootActivityContainer extends ConfigurationContainer
* @return The stack to use for the launch or INVALID_STACK_ID.
*/
ActivityStack getLaunchStack(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
+ @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
int realCallingUid) {
int taskId = INVALID_TASK_ID;
@@ -1666,7 +1669,7 @@ class RootActivityContainer extends ConfigurationContainer
if (taskId != INVALID_TASK_ID) {
// Temporarily set the task id to invalid in case in re-entry.
options.setLaunchTaskId(INVALID_TASK_ID);
- final TaskRecord task = anyTaskForId(taskId,
+ final Task task = anyTaskForId(taskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
options.setLaunchTaskId(taskId);
if (task != null) {
@@ -1765,7 +1768,7 @@ class RootActivityContainer extends ConfigurationContainer
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
- @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options,
+ @Nullable Task candidateTask, @Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
if (activityDisplay == null) {
@@ -1780,8 +1783,7 @@ class RootActivityContainer extends ConfigurationContainer
// If {@code r} is already in target display and its task is the same as the candidate task,
// the intention should be getting a launch stack for the reusable activity, so we can use
// the existing stack.
- if (candidateTask != null
- && (r.getTaskRecord() == null || r.getTaskRecord() == candidateTask)) {
+ if (candidateTask != null && (r.getTask() == null || r.getTask() == candidateTask)) {
final int attachedDisplayId = r.getDisplayId();
if (attachedDisplayId == INVALID_DISPLAY || attachedDisplayId == displayId) {
return candidateTask.getStack();
@@ -1846,7 +1848,7 @@ class RootActivityContainer extends ConfigurationContainer
}
int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable TaskRecord task) {
+ @Nullable Task task) {
// Preference is given to the activity type for the activity then the task since the type
// once set shouldn't change.
int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
@@ -2103,9 +2105,9 @@ class RootActivityContainer extends ConfigurationContainer
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- final List<TaskRecord> tasks = stack.getAllTasks();
+ final List<Task> tasks = stack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
- final TaskRecord task = tasks.get(taskNdx);
+ final Task task = tasks.get(taskNdx);
// Check the task for a top activity belonging to userId, or returning a
// result to an activity belonging to userId. Example case: a document
@@ -2133,7 +2135,7 @@ class RootActivityContainer extends ConfigurationContainer
*
* @return {@code true} if the top activity looks like it belongs to {@param userId}.
*/
- private boolean taskTopActivityIsUser(TaskRecord task, @UserIdInt int userId) {
+ private boolean taskTopActivityIsUser(Task task, @UserIdInt int userId) {
// To handle the case that work app is in the task but just is not the top one.
final ActivityRecord activityRecord = task.getTopActivity();
final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
@@ -2152,22 +2154,22 @@ class RootActivityContainer extends ConfigurationContainer
}
}
- TaskRecord anyTaskForId(int id) {
+ Task anyTaskForId(int id) {
return anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
}
- TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
+ Task anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
return anyTaskForId(id, matchMode, null, !ON_TOP);
}
/**
- * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise.
+ * Returns a {@link Task} for the input id if available. {@code null} otherwise.
* @param id Id of the task we would like returned.
* @param matchMode The mode to match the given task id in.
* @param aOptions The activity options to use for restoration. Can be null.
* @param onTop If the stack for the task should be the topmost on the display.
*/
- TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode,
+ Task anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode,
@Nullable ActivityOptions aOptions, boolean onTop) {
// If options are set, ensure that we are attempting to actually restore a task
if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
@@ -2180,7 +2182,7 @@ class RootActivityContainer extends ConfigurationContainer
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- final TaskRecord task = stack.taskForIdLocked(id);
+ final Task task = stack.taskForIdLocked(id);
if (task == null) {
continue;
}
@@ -2208,7 +2210,7 @@ class RootActivityContainer extends ConfigurationContainer
// Otherwise, check the recent tasks and return if we find it there and we are not restoring
// the task from recents
if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
- final TaskRecord task = mStackSupervisor.mRecentTasks.getTask(id);
+ final Task task = mStackSupervisor.mRecentTasks.getTask(id);
if (task == null) {
if (DEBUG_RECENTS) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 149bcfb991ea..63b11ffe158d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -818,10 +818,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (mWmService.mStrictModeFlash != null) {
mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
}
- if (mWmService.mCircularDisplayMask != null) {
- mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
- mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
- }
if (mWmService.mEmulatorDisplayOverlay != null) {
mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 81a85476c53a..f2678bbf0c9f 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -33,11 +33,11 @@ import java.util.TreeSet;
class RunningTasks {
// Comparator to sort by last active time (descending)
- private static final Comparator<TaskRecord> LAST_ACTIVE_TIME_COMPARATOR =
+ private static final Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR =
(o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
- private final TreeSet<TaskRecord> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
- private final ArrayList<TaskRecord> mTmpStackTasks = new ArrayList<>();
+ private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
+ private final ArrayList<Task> mTmpStackTasks = new ArrayList<>();
void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
@WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
@@ -62,13 +62,13 @@ class RunningTasks {
}
// Take the first {@param maxNum} tasks and create running task infos for them
- final Iterator<TaskRecord> iter = mTmpSortedSet.iterator();
+ final Iterator<Task> iter = mTmpSortedSet.iterator();
while (iter.hasNext()) {
if (maxNum == 0) {
break;
}
- final TaskRecord task = iter.next();
+ final Task task = iter.next();
list.add(createRunningTaskInfo(task));
maxNum--;
}
@@ -77,7 +77,7 @@ class RunningTasks {
/**
* Constructs a {@link RunningTaskInfo} from a given {@param task}.
*/
- private RunningTaskInfo createRunningTaskInfo(TaskRecord task) {
+ private RunningTaskInfo createRunningTaskInfo(Task task) {
final RunningTaskInfo rti = new RunningTaskInfo();
task.fillTaskInfo(rti);
// Fill in some deprecated values
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 7135b21d507d..c0432b679e86 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -155,11 +155,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets,
+ Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
- outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
+ outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
@@ -168,7 +168,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- new Rect() /* outFrame */, outContentInsets, outStableInsets, null /* outOutsets */,
+ new Rect() /* outFrame */, outContentInsets, outStableInsets,
new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
outInsetsState);
}
@@ -186,8 +186,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
- Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
- Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+ Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
+ Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
@@ -195,8 +195,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
- outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
- outStableInsets, outsets, outBackdropFrame, cutout,
+ outFrame, outContentInsets, outVisibleInsets,
+ outStableInsets, outBackdropFrame, cutout,
mergedConfiguration, outSurfaceControl, outInsetsState);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7de845607a9e..520c26e65fee 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,54 +17,318 @@
package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.EMPTY;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static com.android.server.EventLogTags.WM_TASK_CREATED;
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
+import static com.android.server.am.TaskRecordProto.ACTIVITIES;
+import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
+import static com.android.server.am.TaskRecordProto.FULLSCREEN;
+import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
+import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
+import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
+import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
+import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.am.TaskRecordProto.TASK;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
+import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
-import static com.android.server.wm.TaskProto.BOUNDS;
import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
-import static com.android.server.wm.TaskProto.ID;
import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.CallSuper;
+import static java.lang.Integer.MAX_VALUE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.AppGlobals;
+import android.app.TaskInfo;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Debug;
import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.XmlUtils;
+import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.ActivityStack.ActivityState;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Objects;
import java.util.function.Consumer;
-class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{
- static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
+class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
+ private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
+ private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+ private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
+ private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+
+ private static final String ATTR_TASKID = "task_id";
+ private static final String TAG_INTENT = "intent";
+ private static final String TAG_AFFINITYINTENT = "affinity_intent";
+ private static final String ATTR_REALACTIVITY = "real_activity";
+ private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
+ private static final String ATTR_ORIGACTIVITY = "orig_activity";
+ private static final String TAG_ACTIVITY = "activity";
+ private static final String ATTR_AFFINITY = "affinity";
+ private static final String ATTR_ROOT_AFFINITY = "root_affinity";
+ private static final String ATTR_ROOTHASRESET = "root_has_reset";
+ private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
+ private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
+ private static final String ATTR_USERID = "user_id";
+ private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
+ private static final String ATTR_EFFECTIVE_UID = "effective_uid";
+ @Deprecated
+ private static final String ATTR_TASKTYPE = "task_type";
+ private static final String ATTR_LASTDESCRIPTION = "last_description";
+ private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
+ private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
+ private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
+ private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
+ private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
+ private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
+ private static final String ATTR_CALLING_UID = "calling_uid";
+ private static final String ATTR_CALLING_PACKAGE = "calling_package";
+ private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
+ private static final String ATTR_RESIZE_MODE = "resize_mode";
+ private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
+ private static final String ATTR_MIN_WIDTH = "min_width";
+ private static final String ATTR_MIN_HEIGHT = "min_height";
+ private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
+
+ // Current version of the task record we persist. Used to check if we need to run any upgrade
+ // code.
+ private static final int PERSIST_TASK_VERSION = 1;
+
+ private static final int INVALID_MIN_SIZE = -1;
+
+ /**
+ * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ REPARENT_MOVE_STACK_TO_FRONT,
+ REPARENT_KEEP_STACK_AT_FRONT,
+ REPARENT_LEAVE_STACK_IN_PLACE
+ })
+ @interface ReparentMoveStackMode {}
+ // Moves the stack to the front if it was not at the front
+ static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
+ // Only moves the stack to the front if it was focused or front most already
+ static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
+ // Do not move the stack as a part of reparenting
+ static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
+
+ /**
+ * The factory used to create {@link Task}. This allows OEM subclass {@link Task}.
+ */
+ private static TaskFactory sTaskFactory;
+
+ String affinity; // The affinity name for this task, or null; may change identity.
+ String rootAffinity; // Initial base affinity, or null; does not change from initial root.
+ final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
+ final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
+ Intent intent; // The original intent that started the task. Note that this value can
+ // be null.
+ Intent affinityIntent; // Intent of affinity-moved activity that started this task.
+ int effectiveUid; // The current effective uid of the identity of this task.
+ ComponentName origActivity; // The non-alias activity component of the intent.
+ ComponentName realActivity; // The actual activity component that started the task.
+ boolean realActivitySuspended; // True if the actual activity component that started the
+ // task is suspended.
+ boolean inRecents; // Actually in the recents list?
+ long lastActiveTime; // Last time this task was active in the current device session,
+ // including sleep. This time is initialized to the elapsed time when
+ // restored from disk.
+ boolean isAvailable; // Is the activity available to be launched?
+ boolean rootWasReset; // True if the intent at the root of the task had
+ // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
+ boolean autoRemoveRecents; // If true, we should automatically remove the task from
+ // recents when activity finishes
+ boolean askedCompatMode;// Have asked the user about compat mode for this task.
+ boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
+
+ String stringName; // caching of toString() result.
+ boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
+ // was changed.
+
+ int numFullscreen; // Number of fullscreen activities.
+
+ /** Can't be put in lockTask mode. */
+ final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
+ /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
+ final static int LOCK_TASK_AUTH_PINNABLE = 1;
+ /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
+ final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
+ /** Can enter lockTask without user approval. Can start over existing lockTask task. */
+ final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+ * lockTask task. */
+ final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
+ int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+
+ int mLockTaskUid = -1; // The uid of the application that called startLockTask().
+
+ /** Current stack. Setter must always be used to update the value. */
+ private ActivityStack mStack;
+
+ /** The process that had previously hosted the root activity of this task.
+ * Used to know that we should try harder to keep this process around, in case the
+ * user wants to return to it. */
+ private WindowProcessController mRootProcess;
+
+ /** Takes on same value as first root activity */
+ boolean isPersistable = false;
+ int maxRecents;
+
+ /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
+ * determining the order when restoring. Sign indicates whether last task movement was to front
+ * (positive) or back (negative). Absolute value indicates time. */
+ long mLastTimeMoved;
+
+ /** If original intent did not allow relinquishing task identity, save that information */
+ private boolean mNeverRelinquishIdentity = true;
+
+ // Used in the unique case where we are clearing the task in order to reuse it. In that case we
+ // do not want to delete the stack when the task goes empty.
+ private boolean mReuseTask = false;
+
+ CharSequence lastDescription; // Last description captured for this item.
+
+ int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
+ int mAffiliatedTaskColor; // color of the parent task affiliation.
+ Task mPrevAffiliate; // previous task in affiliated chain.
+ int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
+ Task mNextAffiliate; // next task in affiliated chain.
+ int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
+
+ // For relaunching the task from recents as though it was launched by the original launcher.
+ int mCallingUid;
+ String mCallingPackage;
+
+ private final Rect mTmpStableBounds = new Rect();
+ private final Rect mTmpNonDecorBounds = new Rect();
+ private final Rect mTmpBounds = new Rect();
+ private final Rect mTmpInsets = new Rect();
+
+ // Last non-fullscreen bounds the task was launched in or resized to.
+ // The information is persisted and used to determine the appropriate stack to launch the
+ // task into on restore.
+ Rect mLastNonFullscreenBounds = null;
+ // Minimal width and height of this task when it's resizeable. -1 means it should use the
+ // default minimal width/height.
+ int mMinWidth;
+ int mMinHeight;
+
+ // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
+ // This number will be assigned when we evaluate OOM scores for all visible tasks.
+ int mLayerRank = -1;
+
+ /** Helper object used for updating override configuration. */
+ private Configuration mTmpConfig = new Configuration();
+
+ /** Used by fillTaskInfo */
+ final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
final ActivityTaskManagerService mAtmService;
@@ -122,22 +386,1844 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
/** @see #setCanAffectSystemUiFlags */
private boolean mCanAffectSystemUiFlags = true;
- Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture,
- TaskDescription taskDescription, ActivityTaskManagerService atm) {
- super(atm.mWindowManager);
- mAtmService = atm;
- mTaskId = taskId;
- mUserId = userId;
+ /**
+ * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
+ * ActivityInfo, Intent, TaskDescription)} instead.
+ */
+ Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+ TaskDescription _taskDescription, ActivityStack stack) {
+ this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
+ null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
+ false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
+ UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
+ null /*_lastDescription*/, System.currentTimeMillis(),
+ true /*neverRelinquishIdentity*/,
+ _taskDescription != null ? _taskDescription : new TaskDescription(),
+ _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
+ info.applicationInfo.uid, info.packageName, info.resizeMode,
+ info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
+ false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
+ _voiceSession, _voiceInteractor, stack);
+ }
+
+ /** Don't use constructor directly. This is only used by XML parser. */
+ Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
+ Intent _affinityIntent, String _affinity, String _rootAffinity,
+ ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
+ boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
+ int _effectiveUid, String _lastDescription,
+ long lastTimeMoved, boolean neverRelinquishIdentity,
+ TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
+ int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+ int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
+ boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+ ActivityStack stack) {
+ super(atmService.mWindowManager);
+
+ EventLog.writeEvent(WM_TASK_CREATED, _taskId,
+ stack != null ? stack.mStackId : INVALID_STACK_ID);
+ mAtmService = atmService;
+ mTaskId = _taskId;
+ mUserId = _userId;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
- mTaskDescription = taskDescription;
- EventLog.writeEvent(WM_TASK_CREATED, mTaskId,
- stack != null ? stack.mStackId : INVALID_STACK_ID);
-
+ mTaskDescription = _lastTaskDescription;
// Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
setOrientation(SCREEN_ORIENTATION_UNSET);
- // TODO(task-merge): Is this really needed?
- //setBounds(getResolvedOverrideBounds());
+ mRemoteToken = new RemoteToken(this);
+ affinityIntent = _affinityIntent;
+ affinity = _affinity;
+ rootAffinity = _rootAffinity;
+ voiceSession = _voiceSession;
+ voiceInteractor = _voiceInteractor;
+ realActivity = _realActivity;
+ realActivitySuspended = _realActivitySuspended;
+ origActivity = _origActivity;
+ rootWasReset = _rootWasReset;
+ isAvailable = true;
+ autoRemoveRecents = _autoRemoveRecents;
+ askedCompatMode = _askedCompatMode;
+ mUserSetupComplete = userSetupComplete;
+ effectiveUid = _effectiveUid;
+ touchActiveTime();
+ lastDescription = _lastDescription;
+ mLastTimeMoved = lastTimeMoved;
+ mNeverRelinquishIdentity = neverRelinquishIdentity;
+ mAffiliatedTaskId = taskAffiliation;
+ mAffiliatedTaskColor = taskAffiliationColor;
+ mPrevAffiliateTaskId = prevTaskId;
+ mNextAffiliateTaskId = nextTaskId;
+ mCallingUid = callingUid;
+ mCallingPackage = callingPackage;
+ mResizeMode = resizeMode;
+ if (info != null) {
+ setIntent(_intent, info);
+ setMinDimensions(info);
+ } else {
+ intent = _intent;
+ mMinWidth = minWidth;
+ mMinHeight = minHeight;
+ }
+ mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
+ }
+
+ void cleanUpResourcesForDestroy() {
+ if (hasChild()) {
+ return;
+ }
+
+ // This task is going away, so save the last state if necessary.
+ saveLaunchingStateIfNeeded();
+
+ // TODO: VI what about activity?
+ final boolean isVoiceSession = voiceSession != null;
+ if (isVoiceSession) {
+ try {
+ voiceSession.taskFinished(intent, mTaskId);
+ } catch (RemoteException e) {
+ }
+ }
+ if (autoRemoveFromRecents() || isVoiceSession) {
+ // Task creator asked to remove this when done, or this task was a voice
+ // interaction, so it should not remain on the recent tasks list.
+ mAtmService.mStackSupervisor.mRecentTasks.remove(this);
+ }
+
+ removeIfPossible();
+ }
+
+ @VisibleForTesting
+ @Override
+ void removeIfPossible() {
+ mAtmService.getLockTaskController().clearLockedTask(this);
+ if (shouldDeferRemoval()) {
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+ return;
+ }
+ removeImmediately();
+ mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
+ }
+
+ void setResizeMode(int resizeMode) {
+ if (mResizeMode == resizeMode) {
+ return;
+ }
+ mResizeMode = resizeMode;
+ mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ updateTaskDescription();
+ }
+
+ boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
+ mAtmService.deferWindowLayout();
+
+ try {
+ final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
+
+ if (getParent() == null) {
+ // Task doesn't exist in window manager yet (e.g. was restored from recents).
+ // All we can do for now is update the bounds so it can be used when the task is
+ // added to window manager.
+ setBounds(bounds);
+ if (!inFreeformWindowingMode()) {
+ // re-restore the task so it can have the proper stack association.
+ mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
+ }
+ return true;
+ }
+
+ if (!canResizeToBounds(bounds)) {
+ throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
+ + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
+ }
+
+ // Do not move the task to another stack here.
+ // This method assumes that the task is already placed in the right stack.
+ // we do not mess with that decision and we only do the resize!
+
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
+
+ boolean updatedConfig = false;
+ mTmpConfig.setTo(getResolvedOverrideConfiguration());
+ if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
+ updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
+ }
+ // This variable holds information whether the configuration didn't change in a
+ // significant way and the activity was kept the way it was. If it's false, it means
+ // the activity had to be relaunched due to configuration change.
+ boolean kept = true;
+ if (updatedConfig) {
+ final ActivityRecord r = topRunningActivityLocked();
+ if (r != null && !deferResume) {
+ kept = r.ensureActivityConfiguration(0 /* globalChanges */,
+ preserveWindow);
+ // Preserve other windows for resizing because if resizing happens when there
+ // is a dialog activity in the front, the activity that still shows some
+ // content to the user will become black and cause flickers. Note in most cases
+ // this won't cause tons of irrelevant windows being preserved because only
+ // activities in this task may experience a bounds change. Configs for other
+ // activities stay the same.
+ mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0,
+ preserveWindow);
+ if (!kept) {
+ mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ }
+ }
+ }
+ resize(kept, forced);
+
+ saveLaunchingStateIfNeeded();
+
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ return kept;
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+ }
+
+ /** Convenience method to reparent a task to the top or bottom position of the stack. */
+ boolean reparent(ActivityStack preferredStack, boolean toTop,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ String reason) {
+ return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
+ true /* schedulePictureInPictureModeChange */, reason);
+ }
+
+ /**
+ * Convenience method to reparent a task to the top or bottom position of the stack, with
+ * an option to skip scheduling the picture-in-picture mode change.
+ */
+ boolean reparent(ActivityStack preferredStack, boolean toTop,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ boolean schedulePictureInPictureModeChange, String reason) {
+ return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
+ deferResume, schedulePictureInPictureModeChange, reason);
+ }
+
+ /** Convenience method to reparent a task to a specific position of the stack. */
+ boolean reparent(ActivityStack preferredStack, int position,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ String reason) {
+ return reparent(preferredStack, position, moveStackMode, animate, deferResume,
+ true /* schedulePictureInPictureModeChange */, reason);
+ }
+
+ /**
+ * Reparents the task into a preferred stack, creating it if necessary.
+ *
+ * @param preferredStack the target stack to move this task
+ * @param position the position to place this task in the new stack
+ * @param animate whether or not we should wait for the new window created as a part of the
+ * reparenting to be drawn and animated in
+ * @param moveStackMode whether or not to move the stack to the front always, only if it was
+ * previously focused & in front, or never
+ * @param deferResume whether or not to update the visibility of other tasks and stacks that may
+ * have changed as a result of this reparenting
+ * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
+ * change. Callers may set this to false if they are explicitly scheduling PiP mode
+ * changes themselves, like during the PiP animation
+ * @param reason the caller of this reparenting
+ * @return whether the task was reparented
+ */
+ // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
+ // re-parenting the task. Can only be done when we are no longer using static stack Ids.
+ boolean reparent(ActivityStack preferredStack, int position,
+ @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ boolean schedulePictureInPictureModeChange, String reason) {
+ final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
+ final RootActivityContainer root = mAtmService.mRootActivityContainer;
+ final WindowManagerService windowManager = mAtmService.mWindowManager;
+ final ActivityStack sourceStack = getStack();
+ final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
+ position == MAX_VALUE);
+ if (toStack == sourceStack) {
+ return false;
+ }
+ if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
+ return false;
+ }
+
+ final boolean toTopOfStack = position == MAX_VALUE;
+ if (toTopOfStack && toStack.getResumedActivity() != null
+ && toStack.topRunningActivityLocked() != null) {
+ // Pause the resumed activity on the target stack while re-parenting task on top of it.
+ toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+ null /* resuming */);
+ }
+
+ final int toStackWindowingMode = toStack.getWindowingMode();
+ final ActivityRecord topActivity = getTopActivity();
+
+ final boolean mightReplaceWindow = topActivity != null
+ && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
+ if (mightReplaceWindow) {
+ // We are about to relaunch the activity because its configuration changed due to
+ // being maximized, i.e. size change. The activity will first remove the old window
+ // and then add a new one. This call will tell window manager about this, so it can
+ // preserve the old window until the new one is drawn. This prevents having a gap
+ // between the removal and addition, in which no window is visible. We also want the
+ // entrance of the new window to be properly animated.
+ // Note here we always set the replacing window first, as the flags might be needed
+ // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
+ windowManager.setWillReplaceWindow(topActivity.appToken, animate);
+ }
+
+ mAtmService.deferWindowLayout();
+ boolean kept = true;
+ try {
+ final ActivityRecord r = topRunningActivityLocked();
+ final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
+ && (topRunningActivityLocked() == r);
+ final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
+ final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
+
+ // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+ // Whenever we are moving the top activity from the front stack we want to make sure to
+ // move the stack to the front.
+ final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
+ && (sourceStack.topRunningActivityLocked() == r);
+
+ final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
+ || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
+
+ reparent(toStack, position, moveStackToFront, reason);
+
+ if (schedulePictureInPictureModeChange) {
+ // Notify of picture-in-picture mode changes
+ supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
+ }
+
+ // If the task had focus before (or we're requested to move focus), move focus to the
+ // new stack by moving the stack to the front.
+ if (r != null) {
+ toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
+ wasPaused, reason);
+ }
+ if (!animate) {
+ mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
+ }
+
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ // TODO: Should this call be moved inside the resize method in WM?
+ toStack.prepareFreezingTaskBounds();
+
+ // Make sure the task has the appropriate bounds/size for the stack it is in.
+ final boolean toStackSplitScreenPrimary =
+ toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+ final Rect configBounds = getRequestedOverrideBounds();
+ if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
+ || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+ && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
+ kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
+ !mightReplaceWindow, deferResume);
+ } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
+ Rect bounds = getLaunchBounds();
+ if (bounds == null) {
+ mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+ bounds = configBounds;
+ }
+ kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
+ } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
+ if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+ // Move recents to front so it is not behind home stack when going into docked
+ // mode
+ mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
+ }
+ kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
+ !mightReplaceWindow, deferResume);
+ }
+ } finally {
+ mAtmService.continueWindowLayout();
+ }
+
+ if (mightReplaceWindow) {
+ // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
+ // window), we need to clear the replace window settings. Otherwise, we schedule a
+ // timeout to remove the old window if the replacing window is not coming in time.
+ windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
+ }
+
+ if (!deferResume) {
+ // The task might have already been running and its visibility needs to be synchronized
+ // with the visibility of the stack / windows.
+ root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
+ root.resumeFocusedStacksTopActivities();
+ }
+
+ // TODO: Handle incorrect request to move before the actual move, not after.
+ supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
+ DEFAULT_DISPLAY, toStack);
+
+ return (preferredStack == toStack);
+ }
+
+ /**
+ * @return {@code true} if the windows of tasks being moved to the target stack from the
+ * source stack should be replaced, meaning that window manager will keep the old window
+ * around until the new is ready.
+ */
+ private static boolean replaceWindowsOnTaskMove(
+ int sourceWindowingMode, int targetWindowingMode) {
+ return sourceWindowingMode == WINDOWING_MODE_FREEFORM
+ || targetWindowingMode == WINDOWING_MODE_FREEFORM;
+ }
+
+ /**
+ * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
+ */
+ TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
+
+ // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
+ // synchronized between AM and WM.
+ return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
+ restoreFromDisk);
+ }
+
+ void touchActiveTime() {
+ lastActiveTime = SystemClock.elapsedRealtime();
+ }
+
+ long getInactiveDuration() {
+ return SystemClock.elapsedRealtime() - lastActiveTime;
+ }
+
+ /** Sets the original intent, and the calling uid and package. */
+ void setIntent(ActivityRecord r) {
+ mCallingUid = r.launchedFromUid;
+ mCallingPackage = r.launchedFromPackage;
+ setIntent(r.intent, r.info);
+ setLockTaskAuth(r);
+ }
+
+ /** Sets the original intent, _without_ updating the calling uid or package. */
+ private void setIntent(Intent _intent, ActivityInfo info) {
+ if (intent == null) {
+ mNeverRelinquishIdentity =
+ (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ } else if (mNeverRelinquishIdentity) {
+ return;
+ }
+
+ affinity = info.taskAffinity;
+ if (intent == null) {
+ // If this task already has an intent associated with it, don't set the root
+ // affinity -- we don't want it changing after initially set, but the initially
+ // set value may be null.
+ rootAffinity = affinity;
+ }
+ effectiveUid = info.applicationInfo.uid;
+ stringName = null;
+
+ if (info.targetActivity == null) {
+ if (_intent != null) {
+ // If this Intent has a selector, we want to clear it for the
+ // recent task since it is not relevant if the user later wants
+ // to re-launch the app.
+ if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
+ _intent = new Intent(_intent);
+ _intent.setSelector(null);
+ _intent.setSourceBounds(null);
+ }
+ }
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
+ intent = _intent;
+ realActivity = _intent != null ? _intent.getComponent() : null;
+ origActivity = null;
+ } else {
+ ComponentName targetComponent = new ComponentName(
+ info.packageName, info.targetActivity);
+ if (_intent != null) {
+ Intent targetIntent = new Intent(_intent);
+ targetIntent.setSelector(null);
+ targetIntent.setSourceBounds(null);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Setting Intent of " + this + " to target " + targetIntent);
+ intent = targetIntent;
+ realActivity = targetComponent;
+ origActivity = _intent.getComponent();
+ } else {
+ intent = null;
+ realActivity = targetComponent;
+ origActivity = new ComponentName(info.packageName, info.name);
+ }
+ }
+
+ final int intentFlags = intent == null ? 0 : intent.getFlags();
+ if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+ // Once we are set to an Intent with this flag, we count this
+ // task as having a true root activity.
+ rootWasReset = true;
+ }
+ mUserId = UserHandle.getUserId(info.applicationInfo.uid);
+ mUserSetupComplete = Settings.Secure.getIntForUser(
+ mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
+ if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+ // If the activity itself has requested auto-remove, then just always do it.
+ autoRemoveRecents = true;
+ } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
+ == FLAG_ACTIVITY_NEW_DOCUMENT) {
+ // If the caller has not asked for the document to be retained, then we may
+ // want to turn on auto-remove, depending on whether the target has set its
+ // own document launch mode.
+ if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
+ autoRemoveRecents = false;
+ } else {
+ autoRemoveRecents = true;
+ }
+ } else {
+ autoRemoveRecents = false;
+ }
+ if (mResizeMode != info.resizeMode) {
+ mResizeMode = info.resizeMode;
+ updateTaskDescription();
+ }
+ mSupportsPictureInPicture = info.supportsPictureInPicture();
+ }
+
+ /** Sets the original minimal width and height. */
+ private void setMinDimensions(ActivityInfo info) {
+ if (info != null && info.windowLayout != null) {
+ mMinWidth = info.windowLayout.minWidth;
+ mMinHeight = info.windowLayout.minHeight;
+ } else {
+ mMinWidth = INVALID_MIN_SIZE;
+ mMinHeight = INVALID_MIN_SIZE;
+ }
+ }
+
+ /**
+ * Return true if the input activity has the same intent filter as the intent this task
+ * record is based on (normally the root activity intent).
+ */
+ boolean isSameIntentFilter(ActivityRecord r) {
+ final Intent intent = new Intent(r.intent);
+ // Make sure the component are the same if the input activity has the same real activity
+ // as the one in the task because either one of them could be the alias activity.
+ if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
+ intent.setComponent(this.intent.getComponent());
+ }
+ return intent.filterEquals(this.intent);
+ }
+
+ boolean returnsToHomeStack() {
+ final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
+ return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
+ }
+
+ void setPrevAffiliate(Task prevAffiliate) {
+ mPrevAffiliate = prevAffiliate;
+ mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
+ }
+
+ void setNextAffiliate(Task nextAffiliate) {
+ mNextAffiliate = nextAffiliate;
+ mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
+ }
+
+ ActivityStack getStack() {
+ return mStack;
+ }
+
+ @Override
+ void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+ // TODO(stack-merge): Remove casts after object merge.
+ final ActivityStack oldStack = ((ActivityStack) oldParent);
+ final ActivityStack newStack = ((ActivityStack) newParent);
+
+ mStack = newStack;
+
+ super.onParentChanged(newParent, oldParent);
+
+ if (oldStack != null) {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord activity = getChildAt(i);
+ oldStack.onActivityRemovedFromStack(activity);
+ }
+
+ if (oldStack.inPinnedWindowingMode()
+ && (newStack == null || !newStack.inPinnedWindowingMode())) {
+ // Notify if a task from the pinned stack is being removed
+ // (or moved depending on the mode).
+ mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+ }
+ }
+
+ if (newStack != null) {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord activity = getChildAt(i);
+ newStack.onActivityAddedToStack(activity);
+ }
+
+ // TODO: Ensure that this is actually necessary here
+ // Notify the voice session if required
+ if (voiceSession != null) {
+ try {
+ voiceSession.taskStarted(intent, mTaskId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ // First time we are adding the task to the system.
+ if (oldParent == null && newParent != null) {
+
+ // TODO: Super random place to be doing this, but aligns with what used to be done
+ // before we unified Task level. Look into if this can be done in a better place.
+ updateOverrideConfigurationFromLaunchBounds();
+ }
+
+ // Task is being removed.
+ if (oldParent != null && newParent == null) {
+ cleanUpResourcesForDestroy();
+ }
+
+
+ // Update task bounds if needed.
+ adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
+
+ if (getWindowConfiguration().windowsAreScaleable()) {
+ // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
+ // while a resize is pending.
+ forceWindowsScaleable(true /* force */);
+ } else {
+ forceWindowsScaleable(false /* force */);
+ }
+
+ mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+ }
+
+ void updateTaskMovement(boolean toFront) {
+ if (isPersistable) {
+ mLastTimeMoved = System.currentTimeMillis();
+ // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
+ // recently will be most negative, tasks sent to the bottom before that will be less
+ // negative. Similarly for recent tasks moved to the top which will be most positive.
+ if (!toFront) {
+ mLastTimeMoved *= -1;
+ }
+ }
+ mAtmService.mRootActivityContainer.invalidateTaskLayers();
+ }
+
+ /**
+ * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
+ */
+ int getStackId() {
+ return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
+ }
+
+ // Close up recents linked list.
+ private void closeRecentsChain() {
+ if (mPrevAffiliate != null) {
+ mPrevAffiliate.setNextAffiliate(mNextAffiliate);
+ }
+ if (mNextAffiliate != null) {
+ mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
+ }
+ setPrevAffiliate(null);
+ setNextAffiliate(null);
+ }
+
+ void removedFromRecents() {
+ closeRecentsChain();
+ if (inRecents) {
+ inRecents = false;
+ mAtmService.notifyTaskPersisterLocked(this, false);
+ }
+
+ clearRootProcess();
+
+ mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
+ mTaskId, mUserId);
+ }
+
+ void setTaskToAffiliateWith(Task taskToAffiliateWith) {
+ closeRecentsChain();
+ mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
+ mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
+ // Find the end
+ while (taskToAffiliateWith.mNextAffiliate != null) {
+ final Task nextRecents = taskToAffiliateWith.mNextAffiliate;
+ if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
+ Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
+ + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
+ if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
+ nextRecents.setPrevAffiliate(null);
+ }
+ taskToAffiliateWith.setNextAffiliate(null);
+ break;
+ }
+ taskToAffiliateWith = nextRecents;
+ }
+ taskToAffiliateWith.setNextAffiliate(this);
+ setPrevAffiliate(taskToAffiliateWith);
+ setNextAffiliate(null);
+ }
+
+ /** Returns the intent for the root activity for this task */
+ Intent getBaseIntent() {
+ return intent != null ? intent : affinityIntent;
+ }
+
+ /** Returns the first non-finishing activity from the bottom. */
+ ActivityRecord getRootActivity() {
+ final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
+ if (rootActivityIndex == -1) {
+ // There are no non-finishing activities in the task.
+ return null;
+ }
+ return getChildAt(rootActivityIndex);
+ }
+
+ ActivityRecord getTopActivity() {
+ return getTopActivity(true /* includeOverlays */);
+ }
+
+ ActivityRecord getTopActivity(boolean includeOverlays) {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord r = getChildAt(i);
+ if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
+ continue;
+ }
+ return r;
+ }
+ return null;
+ }
+
+ ActivityRecord topRunningActivityLocked() {
+ if (mStack != null) {
+ for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord r = getChildAt(activityNdx);
+ if (!r.finishing && r.okToShowLocked()) {
+ return r;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return true if any activities in this task belongs to input uid.
+ */
+ boolean containsAppUid(int uid) {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord r = getChildAt(i);
+ if (r.getUid() == uid) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
+ if (mStack != null) {
+ for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord r = getChildAt(activityNdx);
+ if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
+ outActivities.add(r);
+ }
+ }
+ }
+ }
+
+ ActivityRecord topRunningActivityWithStartingWindowLocked() {
+ if (mStack != null) {
+ for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord r = getChildAt(activityNdx);
+ if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
+ || r.finishing || !r.okToShowLocked()) {
+ continue;
+ }
+ return r;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the number of running activities, and the number of non-finishing/initializing
+ * activities in the provided {@param reportOut} respectively.
+ */
+ void getNumRunningActivities(TaskActivitiesReport reportOut) {
+ reportOut.reset();
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord r = getChildAt(i);
+ if (r.finishing) {
+ continue;
+ }
+
+ reportOut.base = r;
+
+ // Increment the total number of non-finishing activities
+ reportOut.numActivities++;
+
+ if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
+ reportOut.top = r;
+ // Reset the number of running activities until we hit the first non-initializing
+ // activity
+ reportOut.numRunning = 0;
+ }
+ if (r.attachedToProcess()) {
+ // Increment the number of actually running activities
+ reportOut.numRunning++;
+ }
+ }
+ }
+
+ boolean okToShowLocked() {
+ // NOTE: If {@link Task#topRunningActivity} return is not null then it is
+ // okay to show the activity when locked.
+ return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
+ || topRunningActivityLocked() != null;
+ }
+
+ /**
+ * Reorder the history stack so that the passed activity is brought to the front.
+ */
+ final void moveActivityToFrontLocked(ActivityRecord newTop) {
+ if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
+ + newTop + " to stack at top callers=" + Debug.getCallers(4));
+
+ positionChildAtTop(newTop);
+ updateEffectiveIntent();
+ }
+
+ @Override
+ public int getActivityType() {
+ final int applicationType = super.getActivityType();
+ if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
+ return applicationType;
+ }
+ return getChildAt(0).getActivityType();
+ }
+
+ @Override
+ void addChild(ActivityRecord r, int index) {
+ // If this task had any child before we added this one.
+ boolean hadChild = hasChild();
+
+ index = getAdjustedAddPosition(r, index);
+ super.addChild(r, index);
+
+ ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
+ r.inHistory = true;
+
+ if (r.occludesParent()) {
+ numFullscreen++;
+ }
+ // Only set this based on the first activity
+ if (!hadChild) {
+ if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
+ // Normally non-standard activity type for the activity record will be set when the
+ // object is created, however we delay setting the standard application type until
+ // this point so that the task can set the type for additional activities added in
+ // the else condition below.
+ r.setActivityType(ACTIVITY_TYPE_STANDARD);
+ }
+ setActivityType(r.getActivityType());
+ isPersistable = r.isPersistable();
+ mCallingUid = r.launchedFromUid;
+ mCallingPackage = r.launchedFromPackage;
+ // Clamp to [1, max].
+ maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
+ ActivityTaskManager.getMaxAppRecentsLimitStatic());
+ } else {
+ // Otherwise make all added activities match this one.
+ r.setActivityType(getActivityType());
+ }
+
+ updateEffectiveIntent();
+ if (r.isPersistable()) {
+ mAtmService.notifyTaskPersisterLocked(this, false);
+ }
+
+ // Make sure the list of display UID whitelists is updated
+ // now that this record is in a new task.
+ mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+ }
+
+ void addChild(ActivityRecord r) {
+ addChild(r, Integer.MAX_VALUE /* add on top */);
+ }
+
+ @Override
+ void removeChild(ActivityRecord r) {
+ if (!mChildren.contains(r)) {
+ Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
+ return;
+ }
+
+ super.removeChild(r);
+ if (r.occludesParent()) {
+ numFullscreen--;
+ }
+ if (r.isPersistable()) {
+ mAtmService.notifyTaskPersisterLocked(this, false);
+ }
+
+ if (inPinnedWindowingMode()) {
+ // We normally notify listeners of task stack changes on pause, however pinned stack
+ // activities are normally in the paused state so no notification will be sent there
+ // before the activity is removed. We send it here so instead.
+ mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
+ }
+
+ final String reason = "removeChild";
+ if (hasChild()) {
+ updateEffectiveIntent();
+
+ // The following block can be executed multiple times if there is more than one overlay.
+ // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
+ // of the task by id and exiting early if not found.
+ if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
+ // When destroying a task, tell the supervisor to remove it so that any activity it
+ // has can be cleaned up correctly. This is currently the only place where we remove
+ // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
+ // state into removeChild(), we just clear the task here before the other residual
+ // work.
+ // TODO: If the callers to removeChild() changes such that we have multiple places
+ // where we are destroying the task, move this back into removeChild()
+ mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
+ !REMOVE_FROM_RECENTS, reason);
+ }
+ } else if (!mReuseTask) {
+ // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
+ mStack.removeChild(this, reason);
+ EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+ "removeChild: last r=" + r + " in t=" + this);
+ removeIfPossible();
+ }
+ }
+
+ /**
+ * @return whether or not there are ONLY task overlay activities in the stack.
+ * If {@param excludeFinishing} is set, then ignore finishing activities in the check.
+ * If there are no task overlay activities, this call returns false.
+ */
+ boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
+ int count = 0;
+ for (int i = getChildCount() - 1; i >= 0; i--) {
+ final ActivityRecord r = getChildAt(i);
+ if (excludeFinishing && r.finishing) {
+ continue;
+ }
+ if (!r.mTaskOverlay) {
+ return false;
+ }
+ count++;
+ }
+ return count > 0;
+ }
+
+ boolean autoRemoveFromRecents() {
+ // We will automatically remove the task either if it has explicitly asked for
+ // this, or it is empty and has never contained an activity that got shown to
+ // the user.
+ return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
+ }
+
+ /**
+ * Completely remove all activities associated with an existing
+ * task starting at a specified index.
+ */
+ private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
+ int numActivities = getChildCount();
+ for ( ; activityNdx < numActivities; ++activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ if (mStack == null) {
+ // Task was restored from persistent storage.
+ r.takeFromHistory();
+ removeChild(r);
+ --activityNdx;
+ --numActivities;
+ } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
+ false /* oomAdj */)
+ == FINISH_RESULT_REMOVED) {
+ --activityNdx;
+ --numActivities;
+ }
+ }
+ }
+
+ /**
+ * Completely remove all activities associated with an existing task.
+ */
+ void performClearTaskLocked() {
+ mReuseTask = true;
+ performClearTaskAtIndexLocked(0, "clear-task-all");
+ mReuseTask = false;
+ }
+
+ ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
+ mReuseTask = true;
+ final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
+ mReuseTask = false;
+ return result;
+ }
+
+ /**
+ * Perform clear operation as requested by
+ * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
+ * stack to the given task, then look for
+ * an instance of that activity in the stack and, if found, finish all
+ * activities on top of it and return the instance.
+ *
+ * @param newR Description of the new activity being started.
+ * @return Returns the old activity that should be continued to be used,
+ * or {@code null} if none was found.
+ */
+ final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+ int numActivities = getChildCount();
+ for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord r = getChildAt(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ if (r.mActivityComponent.equals(newR.mActivityComponent)) {
+ // Here it is! Now finish everything in front...
+ final ActivityRecord ret = r;
+
+ for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
+ r = getChildAt(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
+ if (opts != null) {
+ ret.updateOptionsLocked(opts);
+ }
+ if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
+ == FINISH_RESULT_REMOVED) {
+ --activityNdx;
+ --numActivities;
+ }
+ }
+
+ // Finally, if this is a normal launch mode (that is, not
+ // expecting onNewIntent()), then we will finish the current
+ // instance of the activity so a new fresh one can be started.
+ if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+ && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
+ && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
+ if (!ret.finishing) {
+ ret.finishIfPossible("clear-task-top", false /* oomAdj */);
+ return null;
+ }
+ }
+
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ void removeTaskActivitiesLocked(String reason) {
+ // Just remove the entire task.
+ performClearTaskAtIndexLocked(0, reason);
+ }
+
+ String lockTaskAuthToString() {
+ switch (mLockTaskAuth) {
+ case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
+ case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
+ case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
+ case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
+ default: return "unknown=" + mLockTaskAuth;
+ }
+ }
+
+ void setLockTaskAuth() {
+ setLockTaskAuth(getRootActivity());
+ }
+
+ private void setLockTaskAuth(@Nullable ActivityRecord r) {
+ if (r == null) {
+ mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+ return;
+ }
+
+ final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
+ final LockTaskController lockTaskController = mAtmService.getLockTaskController();
+ switch (r.lockTaskLaunchMode) {
+ case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+ mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+ ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_NEVER:
+ mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+ mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
+ mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+ ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+ break;
+ }
+ if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
+ + " mLockTaskAuth=" + lockTaskAuthToString());
+ }
+
+ @Override
+ public boolean supportsSplitScreenWindowingMode() {
+ // A task can not be docked even if it is considered resizeable because it only supports
+ // picture-in-picture mode but has a non-resizeable resizeMode
+ return super.supportsSplitScreenWindowingMode()
+ // TODO(task-group): Probably makes sense to move this and associated code into
+ // WindowContainer so it affects every node.
+ && mAtmService.mSupportsSplitScreenMultiWindow
+ && (mAtmService.mForceResizableActivities
+ || (isResizeable(false /* checkSupportsPip */)
+ && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
+ }
+
+ /**
+ * Check whether this task can be launched on the specified display.
+ *
+ * @param displayId Target display id.
+ * @return {@code true} if either it is the default display or this activity can be put on a
+ * secondary display.
+ */
+ boolean canBeLaunchedOnDisplay(int displayId) {
+ return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
+ -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
+ }
+
+ /**
+ * Check that a given bounds matches the application requested orientation.
+ *
+ * @param bounds The bounds to be tested.
+ * @return True if the requested bounds are okay for a resizing request.
+ */
+ private boolean canResizeToBounds(Rect bounds) {
+ if (bounds == null || !inFreeformWindowingMode()) {
+ // Note: If not on the freeform workspace, we ignore the bounds.
+ return true;
+ }
+ final boolean landscape = bounds.width() > bounds.height();
+ final Rect configBounds = getRequestedOverrideBounds();
+ if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
+ return configBounds.isEmpty()
+ || landscape == (configBounds.width() > configBounds.height());
+ }
+ return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
+ && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
+ }
+
+ /**
+ * @return {@code true} if the task is being cleared for the purposes of being reused.
+ */
+ boolean isClearingToReuseTask() {
+ return mReuseTask;
+ }
+
+ /**
+ * Find the activity in the history stack within the given task. Returns
+ * the index within the history at which it's found, or < 0 if not found.
+ */
+ final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
+ final ComponentName realActivity = r.mActivityComponent;
+ for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord candidate = getChildAt(activityNdx);
+ if (candidate.finishing) {
+ continue;
+ }
+ if (candidate.mActivityComponent.equals(realActivity)) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+
+ /** Updates the last task description values. */
+ void updateTaskDescription() {
+ // TODO(AM refactor): Cleanup to use findRootIndex()
+ // Traverse upwards looking for any break between main task activities and
+ // utility activities.
+ int activityNdx;
+ final int numActivities = getChildCount();
+ final boolean relinquish = numActivities != 0
+ && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
+ for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ // This will be the top activity for determining taskDescription. Pre-inc to
+ // overcome initial decrement below.
+ ++activityNdx;
+ break;
+ }
+ if (r.intent != null
+ && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+ break;
+ }
+ }
+ if (activityNdx > 0) {
+ // Traverse downwards starting below break looking for set label, icon.
+ // Note that if there are activities in the task but none of them set the
+ // recent activity values, then we do not fall back to the last set
+ // values in the Task.
+ String label = null;
+ String iconFilename = null;
+ int iconResource = -1;
+ int colorPrimary = 0;
+ int colorBackground = 0;
+ int statusBarColor = 0;
+ int navigationBarColor = 0;
+ boolean statusBarContrastWhenTransparent = false;
+ boolean navigationBarContrastWhenTransparent = false;
+ boolean topActivity = true;
+ for (--activityNdx; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (r.mTaskOverlay) {
+ continue;
+ }
+ if (r.taskDescription != null) {
+ if (label == null) {
+ label = r.taskDescription.getLabel();
+ }
+ if (iconResource == -1) {
+ iconResource = r.taskDescription.getIconResource();
+ }
+ if (iconFilename == null) {
+ iconFilename = r.taskDescription.getIconFilename();
+ }
+ if (colorPrimary == 0) {
+ colorPrimary = r.taskDescription.getPrimaryColor();
+ }
+ if (topActivity) {
+ colorBackground = r.taskDescription.getBackgroundColor();
+ statusBarColor = r.taskDescription.getStatusBarColor();
+ navigationBarColor = r.taskDescription.getNavigationBarColor();
+ statusBarContrastWhenTransparent =
+ r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
+ navigationBarContrastWhenTransparent =
+ r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
+ }
+ }
+ topActivity = false;
+ }
+ final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
+ iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+ statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
+ mResizeMode, mMinWidth, mMinHeight);
+ setTaskDescription(taskDescription);
+ // Update the task affiliation color if we are the parent of the group
+ if (mTaskId == mAffiliatedTaskId) {
+ mAffiliatedTaskColor = taskDescription.getPrimaryColor();
+ }
+ mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
+ getTaskInfo());
+ }
+ }
+
+ /**
+ * Find the index of the root activity in the task. It will be the first activity from the
+ * bottom that is not finishing.
+ *
+ * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
+ * activity that defines the task identity (its base intent). It's the
+ * first one that does not have
+ * {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
+ * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
+ * activity was found.
+ */
+ int findRootIndex(boolean effectiveRoot) {
+ int effectiveNdx = -1;
+ final int topActivityNdx = getChildCount() - 1;
+ for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ effectiveNdx = activityNdx;
+ if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ break;
+ }
+ }
+ return effectiveNdx;
+ }
+
+ // TODO (AM refactor): Invoke automatically when there is a change in children
+ @VisibleForTesting
+ void updateEffectiveIntent() {
+ int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
+ if (effectiveRootIndex == -1) {
+ // All activities in the task are either finishing or relinquish task identity.
+ // But we still want to update the intent, so let's use the bottom activity.
+ effectiveRootIndex = 0;
+ }
+ final ActivityRecord r = getChildAt(effectiveRootIndex);
+ setIntent(r);
+
+ // Update the task description when the activities change
+ updateTaskDescription();
+ }
+
+ void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
+ if (bounds == null) {
+ return;
+ }
+ int minWidth = mMinWidth;
+ int minHeight = mMinHeight;
+ // If the task has no requested minimal size, we'd like to enforce a minimal size
+ // so that the user can not render the task too small to manipulate. We don't need
+ // to do this for the pinned stack as the bounds are controlled by the system.
+ if (!inPinnedWindowingMode() && mStack != null) {
+ final int defaultMinSizeDp =
+ mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
+ final ActivityDisplay display =
+ mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
+ final float density =
+ (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+ final int defaultMinSize = (int) (defaultMinSizeDp * density);
+
+ if (minWidth == INVALID_MIN_SIZE) {
+ minWidth = defaultMinSize;
+ }
+ if (minHeight == INVALID_MIN_SIZE) {
+ minHeight = defaultMinSize;
+ }
+ }
+ final boolean adjustWidth = minWidth > bounds.width();
+ final boolean adjustHeight = minHeight > bounds.height();
+ if (!(adjustWidth || adjustHeight)) {
+ return;
+ }
+
+ if (adjustWidth) {
+ if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
+ bounds.left = bounds.right - minWidth;
+ } else {
+ // Either left bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping left.
+ bounds.right = bounds.left + minWidth;
+ }
+ }
+ if (adjustHeight) {
+ if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
+ bounds.top = bounds.bottom - minHeight;
+ } else {
+ // Either top bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping top.
+ bounds.bottom = bounds.top + minHeight;
+ }
+ }
+ }
+
+ void setLastNonFullscreenBounds(Rect bounds) {
+ if (mLastNonFullscreenBounds == null) {
+ mLastNonFullscreenBounds = new Rect(bounds);
+ } else {
+ mLastNonFullscreenBounds.set(bounds);
+ }
+ }
+
+ /**
+ * This should be called when an child activity changes state. This should only
+ * be called from
+ * {@link ActivityRecord#setState(ActivityState, String)} .
+ * @param record The {@link ActivityRecord} whose state has changed.
+ * @param state The new state.
+ * @param reason The reason for the change.
+ */
+ void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
+ final ActivityStack parent = getStack();
+
+ if (parent != null) {
+ parent.onActivityStateChanged(record, state, reason);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
+ // restore the last recorded non-fullscreen bounds.
+ final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
+ final boolean nextPersistTaskBounds =
+ getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
+ || newParentConfig.windowConfiguration.persistTaskBounds();
+ if (!prevPersistTaskBounds && nextPersistTaskBounds
+ && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
+ // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
+ getRequestedOverrideConfiguration().windowConfiguration
+ .setBounds(mLastNonFullscreenBounds);
+ }
+
+ final boolean wasInMultiWindowMode = inMultiWindowMode();
+ super.onConfigurationChanged(newParentConfig);
+ if (wasInMultiWindowMode != inMultiWindowMode()) {
+ mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
+ }
+
+ // If the configuration supports persistent bounds (eg. Freeform), keep track of the
+ // current (non-fullscreen) bounds for persistence.
+ if (getWindowConfiguration().persistTaskBounds()) {
+ final Rect currentBounds = getRequestedOverrideBounds();
+ if (!currentBounds.isEmpty()) {
+ setLastNonFullscreenBounds(currentBounds);
+ }
+ }
+ // TODO: Should also take care of Pip mode changes here.
+
+ saveLaunchingStateIfNeeded();
+ }
+
+ /**
+ * Saves launching state if necessary so that we can launch the activity to its latest state.
+ * It only saves state if this task has been shown to user and it's in fullscreen or freeform
+ * mode on freeform displays.
+ */
+ void saveLaunchingStateIfNeeded() {
+ if (!hasBeenVisible) {
+ // Not ever visible to user.
+ return;
+ }
+
+ final int windowingMode = getWindowingMode();
+ if (windowingMode != WINDOWING_MODE_FULLSCREEN
+ && windowingMode != WINDOWING_MODE_FREEFORM) {
+ return;
+ }
+
+ // Don't persist state if display isn't in freeform mode. Then the task will be launched
+ // back to its last state in a freeform display when it's launched in a freeform display
+ // next time.
+ if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ return;
+ }
+
+ // Saves the new state so that we can launch the activity at the same location.
+ mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
+ }
+
+ /**
+ * Adjust bounds to stay within stack bounds.
+ *
+ * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
+ * that keep them unchanged, but be contained within the stack bounds.
+ *
+ * @param bounds Bounds to be adjusted.
+ * @param stackBounds Bounds within which the other bounds should remain.
+ * @param overlapPxX The amount of px required to be visible in the X dimension.
+ * @param overlapPxY The amount of px required to be visible in the Y dimension.
+ */
+ private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
+ int overlapPxY) {
+ if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
+ return;
+ }
+
+ // For each side of the parent (eg. left), check if the opposing side of the window (eg.
+ // right) is at least overlap pixels away. If less, offset the window by that difference.
+ int horizontalDiff = 0;
+ // If window is smaller than overlap, use it's smallest dimension instead
+ int overlapLR = Math.min(overlapPxX, bounds.width());
+ if (bounds.right < (stackBounds.left + overlapLR)) {
+ horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
+ } else if (bounds.left > (stackBounds.right - overlapLR)) {
+ horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
+ }
+ int verticalDiff = 0;
+ int overlapTB = Math.min(overlapPxY, bounds.width());
+ if (bounds.bottom < (stackBounds.top + overlapTB)) {
+ verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
+ } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
+ verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
+ }
+ bounds.offset(horizontalDiff, verticalDiff);
+ }
+
+ /**
+ * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
+ * intersectBounds on a side, then the respective side will not be intersected.
+ *
+ * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
+ * inset on that side is no-longer applicable. This scenario happens when a task's minimal
+ * bounds are larger than the provided parent/display bounds.
+ *
+ * @param inOutBounds the bounds to intersect.
+ * @param intersectBounds the bounds to intersect with.
+ * @param intersectInsets insets to apply to intersectBounds before intersecting.
+ */
+ static void intersectWithInsetsIfFits(
+ Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
+ if (inOutBounds.right <= intersectBounds.right) {
+ inOutBounds.right =
+ Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
+ }
+ if (inOutBounds.bottom <= intersectBounds.bottom) {
+ inOutBounds.bottom =
+ Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
+ }
+ if (inOutBounds.left >= intersectBounds.left) {
+ inOutBounds.left =
+ Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
+ }
+ if (inOutBounds.top >= intersectBounds.top) {
+ inOutBounds.top =
+ Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
+ }
+ }
+
+ /**
+ * Gets bounds with non-decor and stable insets applied respectively.
+ *
+ * If bounds overhangs the display, those edges will not get insets. See
+ * {@link #intersectWithInsetsIfFits}
+ *
+ * @param outNonDecorBounds where to place bounds with non-decor insets applied.
+ * @param outStableBounds where to place bounds with stable insets applied.
+ * @param bounds the bounds to inset.
+ */
+ private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
+ DisplayInfo displayInfo) {
+ outNonDecorBounds.set(bounds);
+ outStableBounds.set(bounds);
+ if (getStack() == null || getStack().getDisplay() == null) {
+ return;
+ }
+ DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
+ if (policy == null) {
+ return;
+ }
+ mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+
+ policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
+ intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
+
+ policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
+ intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
+ }
+
+ /**
+ * Asks docked-divider controller for the smallestwidthdp given bounds.
+ * @param bounds bounds to calculate smallestwidthdp for.
+ */
+ private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
+ DisplayContent dc = mStack.getDisplay().mDisplayContent;
+ if (dc != null) {
+ return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
+ }
+ return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+ }
+
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
+ }
+
+ /**
+ * Calculates configuration values used by the client to get resources. This should be run
+ * using app-facing bounds (bounds unmodified by animations or transient interactions).
+ *
+ * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
+ * configuring an "inherit-bounds" window which means that all configuration settings would
+ * just be inherited from the parent configuration.
+ **/
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig,
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ windowingMode = parentConfig.windowConfiguration.getWindowingMode();
+ }
+
+ float density = inOutConfig.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = parentConfig.densityDpi;
+ }
+ density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+
+ final Rect bounds = inOutConfig.windowConfiguration.getBounds();
+ Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds == null || outAppBounds.isEmpty()) {
+ inOutConfig.windowConfiguration.setAppBounds(bounds);
+ outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ }
+ // Non-null compatibility insets means the activity prefers to keep its original size, so
+ // the out bounds doesn't need to be restricted by the parent.
+ final boolean insideParentBounds = compatInsets == null;
+ if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
+ final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
+ if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
+ outAppBounds.intersect(parentAppBounds);
+ }
+ }
+
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
+ || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ if (insideParentBounds && mStack != null) {
+ final DisplayInfo di = new DisplayInfo();
+ mStack.getDisplay().mDisplay.getDisplayInfo(di);
+
+ // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
+ // area, i.e. the screen area without the system bars.
+ // The non decor inset are areas that could never be removed in Honeycomb. See
+ // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
+ calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
+ } else {
+ // Apply the given non-decor and stable insets to calculate the corresponding bounds
+ // for screen size of configuration.
+ int rotation = inOutConfig.windowConfiguration.getRotation();
+ if (rotation == ROTATION_UNDEFINED) {
+ rotation = parentConfig.windowConfiguration.getRotation();
+ }
+ if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
+ mTmpNonDecorBounds.set(bounds);
+ mTmpStableBounds.set(bounds);
+ compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
+ intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
+ compatInsets.mNonDecorInsets[rotation]);
+ intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
+ compatInsets.mStableInsets[rotation]);
+ outAppBounds.set(mTmpNonDecorBounds);
+ } else {
+ // Set to app bounds because it excludes decor insets.
+ mTmpNonDecorBounds.set(outAppBounds);
+ mTmpStableBounds.set(outAppBounds);
+ }
+ }
+
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+ inOutConfig.screenWidthDp = insideParentBounds
+ ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
+ : overrideScreenWidthDp;
+ }
+ if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+ inOutConfig.screenHeightDp = insideParentBounds
+ ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
+ : overrideScreenHeightDp;
+ }
+
+ if (inOutConfig.smallestScreenWidthDp
+ == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+ if (WindowConfiguration.isFloating(windowingMode)) {
+ // For floating tasks, calculate the smallest width from the bounds of the task
+ inOutConfig.smallestScreenWidthDp = (int) (
+ Math.min(bounds.width(), bounds.height()) / density);
+ } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
+ // Iterating across all screen orientations, and return the minimum of the task
+ // width taking into account that the bounds might change because the snap
+ // algorithm snaps to a different value
+ inOutConfig.smallestScreenWidthDp =
+ getSmallestScreenWidthDpForDockedBounds(bounds);
+ }
+ // otherwise, it will just inherit
+ }
+ }
+
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+ inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ }
+ if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+ // For calculating screen layout, we need to use the non-decor inset screen area for the
+ // calculation for compatibility reasons, i.e. screen area without system bars that
+ // could never go away in Honeycomb.
+ final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
+ final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+ // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
+ // override calculation with partial default.
+ // Reducing the screen layout starting from its parent config.
+ final int sl = parentConfig.screenLayout
+ & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
+ final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
+ final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
+ inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
+ }
+ }
+
+ @Override
+ void resolveOverrideConfiguration(Configuration newParentConfig) {
+ mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+ super.resolveOverrideConfiguration(newParentConfig);
+ int windowingMode =
+ getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+ }
+ Rect outOverrideBounds =
+ getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
+ newParentConfig.windowConfiguration.getBounds(),
+ newParentConfig.orientation);
+ }
+
+ if (outOverrideBounds.isEmpty()) {
+ // If the task fills the parent, just inherit all the other configs from parent.
+ return;
+ }
+
+ adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ // by policy, make sure the window remains within parent somewhere
+ final float density =
+ ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
+ final Rect parentBounds =
+ new Rect(newParentConfig.windowConfiguration.getBounds());
+ final ActivityDisplay display = mStack.getDisplay();
+ if (display != null && display.mDisplayContent != null) {
+ // If a freeform window moves below system bar, there is no way to move it again
+ // by touch. Because its caption is covered by system bar. So we exclude them
+ // from stack bounds. and then caption will be shown inside stable area.
+ final Rect stableBounds = new Rect();
+ display.mDisplayContent.getStableRect(stableBounds);
+ parentBounds.intersect(stableBounds);
+ }
+
+ fitWithinBounds(outOverrideBounds, parentBounds,
+ (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
+ (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+
+ // Prevent to overlap caption with stable insets.
+ final int offsetTop = parentBounds.top - outOverrideBounds.top;
+ if (offsetTop > 0) {
+ outOverrideBounds.offset(0, offsetTop);
+ }
+ }
+ computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+ }
+
+ /**
+ * Compute bounds (letterbox or pillarbox) for
+ * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
+ * orientation change and the requested orientation is different from the parent.
+ */
+ void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
+ @NonNull Rect parentBounds, int parentOrientation) {
+ // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
+ outBounds.setEmpty();
+ if (handlesOrientationChangeFromDescendant()) {
+ return;
+ }
+ if (refActivity == null) {
+ // Use the top activity as the reference of orientation. Don't include overlays because
+ // it is usually not the actual content or just temporarily shown.
+ // E.g. ForcedResizableInfoActivity.
+ refActivity = getTopActivity(false /* includeOverlays */);
+ }
+
+ // If the task or the reference activity requires a different orientation (either by
+ // override or activityInfo), make it fit the available bounds by scaling down its bounds.
+ final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
+ final int forcedOrientation =
+ (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
+ ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
+ if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
+ return;
+ }
+
+ final int parentWidth = parentBounds.width();
+ final int parentHeight = parentBounds.height();
+ final float aspect = ((float) parentHeight) / parentWidth;
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ final int height = (int) (parentWidth / aspect);
+ final int top = parentBounds.centerY() - height / 2;
+ outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
+ } else {
+ final int width = (int) (parentHeight * aspect);
+ final int left = parentBounds.centerX() - width / 2;
+ outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+ }
+ }
+
+ Rect updateOverrideConfigurationFromLaunchBounds() {
+ final Rect bounds = getLaunchBounds();
+ setBounds(bounds);
+ if (bounds != null && !bounds.isEmpty()) {
+ // TODO: Review if we actually want to do this - we are setting the launch bounds
+ // directly here.
+ bounds.set(getRequestedOverrideBounds());
+ }
+ return bounds;
+ }
+
+ /** Updates the task's bounds and override configuration to match what is expected for the
+ * input stack. */
+ void updateOverrideConfigurationForStack(ActivityStack inStack) {
+ if (mStack != null && mStack == inStack) {
+ return;
+ }
+
+ if (inStack.inFreeformWindowingMode()) {
+ if (!isResizeable()) {
+ throw new IllegalArgumentException("Can not position non-resizeable task="
+ + this + " in stack=" + inStack);
+ }
+ if (!matchParentBounds()) {
+ return;
+ }
+ if (mLastNonFullscreenBounds != null) {
+ setBounds(mLastNonFullscreenBounds);
+ } else {
+ mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+ }
+ } else {
+ setBounds(inStack.getRequestedOverrideBounds());
+ }
+ }
+
+ /** Returns the bounds that should be used to launch this task. */
+ Rect getLaunchBounds() {
+ if (mStack == null) {
+ return null;
+ }
+
+ final int windowingMode = getWindowingMode();
+ if (!isActivityTypeStandardOrUndefined()
+ || windowingMode == WINDOWING_MODE_FULLSCREEN
+ || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
+ return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
+ } else if (!getWindowConfiguration().persistTaskBounds()) {
+ return mStack.getRequestedOverrideBounds();
+ }
+ return mLastNonFullscreenBounds;
+ }
+
+ void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
+ for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (r.mVisibleRequested) {
+ r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
+ }
+ }
+ }
+
+ void setRootProcess(WindowProcessController proc) {
+ clearRootProcess();
+ if (intent != null
+ && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
+ mRootProcess = proc;
+ mRootProcess.addRecentTask(this);
+ }
+ }
+
+ void clearRootProcess() {
+ if (mRootProcess != null) {
+ mRootProcess.removeRecentTask(this);
+ mRootProcess = null;
+ }
+ }
+
+ void clearAllPendingOptions() {
+ for (int i = getChildCount() - 1; i >= 0; i--) {
+ getChildAt(i).clearOptionsLocked(false /* withAbort */);
+ }
}
@Override
@@ -205,22 +2291,13 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
}
@Override
- void removeIfPossible() {
- if (shouldDeferRemoval()) {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
- return;
- }
- removeImmediately();
- }
-
- @Override
void removeImmediately() {
if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
super.removeImmediately();
}
- // TODO: Consolidate this with TaskRecord.reparent()
+ // TODO: Consolidate this with Task.reparent()
void reparent(TaskStack stack, int position, boolean moveParents, String reason) {
if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + getTaskStack());
@@ -241,8 +2318,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
}
- // TODO(task-merge): Remove cast.
- stack.positionChildAt(position, (TaskRecord) this, moveParents);
+ stack.positionChildAt(position, this, moveParents);
// If we are moving from the fullscreen stack to the pinned stack then we want to preserve
// our insets so that there will not be a jump in the area covered by system decorations.
@@ -444,7 +2520,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
for (int i = mChildren.size() - 1; i >= 0; i--) {
final ActivityRecord token = mChildren.get(i);
// skip hidden (or about to hide) apps
- if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) {
+ if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
continue;
}
final WindowState win = token.findMainWindow();
@@ -662,10 +2738,9 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
ActivityRecord getTopVisibleActivity() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord token = mChildren.get(i);
- // skip hidden (or about to hide) apps
- if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) {
- return token;
+ final ActivityRecord activity = mChildren.get(i);
+ if (!activity.mIsExiting && activity.isClientVisible() && activity.mVisibleRequested) {
+ return activity;
}
}
return null;
@@ -744,7 +2819,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
}
String getName() {
- return toShortString();
+ return "Task=" + mTaskId;
}
void clearPreserveNonFloatingState() {
@@ -778,13 +2853,13 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
final long token = proto.start(fieldId);
super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
- proto.write(ID, mTaskId);
+ proto.write(TaskProto.ID, mTaskId);
for (int i = mChildren.size() - 1; i >= 0; i--) {
final ActivityRecord activity = mChildren.get(i);
activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
}
proto.write(FILLS_PARENT, matchParentBounds());
- getBounds().writeToProto(proto, BOUNDS);
+ getBounds().writeToProto(proto, TaskProto.BOUNDS);
mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
if (mSurfaceControl != null) {
proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
@@ -813,7 +2888,609 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
}
}
- String toShortString() {
- return "Task=" + mTaskId;
+ /**
+ * Fills in a {@link TaskInfo} with information from this task.
+ * @param info the {@link TaskInfo} to fill in
+ */
+ void fillTaskInfo(TaskInfo info) {
+ getNumRunningActivities(mReuseActivitiesReport);
+ info.userId = mUserId;
+ info.stackId = getStackId();
+ info.taskId = mTaskId;
+ info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
+ info.isRunning = getTopActivity() != null;
+ info.baseIntent = new Intent(getBaseIntent());
+ info.baseActivity = mReuseActivitiesReport.base != null
+ ? mReuseActivitiesReport.base.intent.getComponent()
+ : null;
+ info.topActivity = mReuseActivitiesReport.top != null
+ ? mReuseActivitiesReport.top.mActivityComponent
+ : null;
+ info.origActivity = origActivity;
+ info.realActivity = realActivity;
+ info.numActivities = mReuseActivitiesReport.numActivities;
+ info.lastActiveTime = lastActiveTime;
+ info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
+ info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
+ info.resizeMode = mResizeMode;
+ info.configuration.setTo(getConfiguration());
+ }
+
+ /**
+ * Returns a {@link TaskInfo} with information from this task.
+ */
+ ActivityManager.RunningTaskInfo getTaskInfo() {
+ ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ fillTaskInfo(info);
+ return info;
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("userId="); pw.print(mUserId);
+ pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
+ pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
+ pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
+ pw.print(" mCallingPackage="); pw.println(mCallingPackage);
+ if (affinity != null || rootAffinity != null) {
+ pw.print(prefix); pw.print("affinity="); pw.print(affinity);
+ if (affinity == null || !affinity.equals(rootAffinity)) {
+ pw.print(" root="); pw.println(rootAffinity);
+ } else {
+ pw.println();
+ }
+ }
+ if (voiceSession != null || voiceInteractor != null) {
+ pw.print(prefix); pw.print("VOICE: session=0x");
+ pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
+ pw.print(" interactor=0x");
+ pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
+ }
+ if (intent != null) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(prefix); sb.append("intent={");
+ intent.toShortString(sb, false, true, false, false);
+ sb.append('}');
+ pw.println(sb.toString());
+ }
+ if (affinityIntent != null) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(prefix); sb.append("affinityIntent={");
+ affinityIntent.toShortString(sb, false, true, false, false);
+ sb.append('}');
+ pw.println(sb.toString());
+ }
+ if (origActivity != null) {
+ pw.print(prefix); pw.print("origActivity=");
+ pw.println(origActivity.flattenToShortString());
+ }
+ if (realActivity != null) {
+ pw.print(prefix); pw.print("mActivityComponent=");
+ pw.println(realActivity.flattenToShortString());
+ }
+ if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) {
+ pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
+ pw.print(" isPersistable="); pw.print(isPersistable);
+ pw.print(" numFullscreen="); pw.print(numFullscreen);
+ pw.print(" activityType="); pw.println(getActivityType());
+ }
+ if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
+ || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
+ pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
+ pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
+ pw.print(" mReuseTask="); pw.print(mReuseTask);
+ pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
+ }
+ if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
+ || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
+ || mNextAffiliate != null) {
+ pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
+ pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
+ pw.print(" (");
+ if (mPrevAffiliate == null) {
+ pw.print("null");
+ } else {
+ pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
+ }
+ pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
+ pw.print(" (");
+ if (mNextAffiliate == null) {
+ pw.print("null");
+ } else {
+ pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
+ }
+ pw.println(")");
+ }
+ pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
+ if (!askedCompatMode || !inRecents || !isAvailable) {
+ pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
+ pw.print(" inRecents="); pw.print(inRecents);
+ pw.print(" isAvailable="); pw.println(isAvailable);
+ }
+ if (lastDescription != null) {
+ pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
+ }
+ if (mRootProcess != null) {
+ pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
+ }
+ pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
+ pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
+ pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
+ pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
+ pw.print(" isResizeable=" + isResizeable());
+ pw.print(" lastActiveTime=" + lastActiveTime);
+ pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ if (stringName != null) {
+ sb.append(stringName);
+ sb.append(" U=");
+ sb.append(mUserId);
+ sb.append(" StackId=");
+ sb.append(getStackId());
+ sb.append(" sz=");
+ sb.append(getChildCount());
+ sb.append('}');
+ return sb.toString();
+ }
+ sb.append("Task{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" #");
+ sb.append(mTaskId);
+ if (affinity != null) {
+ sb.append(" A=");
+ sb.append(affinity);
+ } else if (intent != null) {
+ sb.append(" I=");
+ sb.append(intent.getComponent().flattenToShortString());
+ } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
+ sb.append(" aI=");
+ sb.append(affinityIntent.getComponent().flattenToShortString());
+ } else {
+ sb.append(" ??");
+ }
+ stringName = sb.toString();
+ return toString();
+ }
+
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId,
+ @WindowTraceLogLevel int logLevel) {
+ if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
+ return;
+ }
+
+ final long token = proto.start(fieldId);
+ writeToProtoInnerTaskOnly(proto, TASK, logLevel);
+ proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
+ for (int i = getChildCount() - 1; i >= 0; i--) {
+ final ActivityRecord activity = getChildAt(i);
+ activity.writeToProto(proto, ACTIVITIES);
+ }
+ proto.write(STACK_ID, getStackId());
+ if (mLastNonFullscreenBounds != null) {
+ mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
+ }
+ if (realActivity != null) {
+ proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
+ }
+ if (origActivity != null) {
+ proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
+ }
+ proto.write(ACTIVITY_TYPE, getActivityType());
+ proto.write(RESIZE_MODE, mResizeMode);
+ // TODO: Remove, no longer needed with windowingMode.
+ proto.write(FULLSCREEN, matchParentBounds());
+
+ if (!matchParentBounds()) {
+ final Rect bounds = getRequestedOverrideBounds();
+ bounds.writeToProto(proto, com.android.server.am.TaskRecordProto.BOUNDS);
+ }
+ proto.write(MIN_WIDTH, mMinWidth);
+ proto.write(MIN_HEIGHT, mMinHeight);
+ proto.end(token);
+ }
+
+ /** @see #getNumRunningActivities(TaskActivitiesReport) */
+ static class TaskActivitiesReport {
+ int numRunning;
+ int numActivities;
+ ActivityRecord top;
+ ActivityRecord base;
+
+ void reset() {
+ numRunning = numActivities = 0;
+ top = base = null;
+ }
+ }
+
+ /**
+ * Saves this {@link Task} to XML using given serializer.
+ */
+ void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+ if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
+
+ out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
+ if (realActivity != null) {
+ out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
+ }
+ out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
+ if (origActivity != null) {
+ out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
+ }
+ // Write affinity, and root affinity if it is different from affinity.
+ // We use the special string "@" for a null root affinity, so we can identify
+ // later whether we were given a root affinity or should just make it the
+ // same as the affinity.
+ if (affinity != null) {
+ out.attribute(null, ATTR_AFFINITY, affinity);
+ if (!affinity.equals(rootAffinity)) {
+ out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+ }
+ } else if (rootAffinity != null) {
+ out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+ }
+ out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
+ out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
+ out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
+ out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
+ out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
+ out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
+ out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+ out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
+ if (lastDescription != null) {
+ out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
+ }
+ if (getTaskDescription() != null) {
+ getTaskDescription().saveToXml(out);
+ }
+ out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
+ out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
+ out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
+ out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
+ out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
+ out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+ out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
+ out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
+ String.valueOf(mSupportsPictureInPicture));
+ if (mLastNonFullscreenBounds != null) {
+ out.attribute(
+ null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
+ }
+ out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
+ out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
+ out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
+
+ if (affinityIntent != null) {
+ out.startTag(null, TAG_AFFINITYINTENT);
+ affinityIntent.saveToXml(out);
+ out.endTag(null, TAG_AFFINITYINTENT);
+ }
+
+ if (intent != null) {
+ out.startTag(null, TAG_INTENT);
+ intent.saveToXml(out);
+ out.endTag(null, TAG_INTENT);
+ }
+
+ final int numActivities = getChildCount();
+ for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+ final ActivityRecord r = getChildAt(activityNdx);
+ if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
+ || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
+ && activityNdx > 0) {
+ // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
+ break;
+ }
+ out.startTag(null, TAG_ACTIVITY);
+ r.saveToXml(out);
+ out.endTag(null, TAG_ACTIVITY);
+ }
+ }
+
+ @VisibleForTesting
+ static TaskFactory getTaskFactory() {
+ if (sTaskFactory == null) {
+ setTaskFactory(new TaskFactory());
+ }
+ return sTaskFactory;
+ }
+
+ static void setTaskFactory(TaskFactory factory) {
+ sTaskFactory = factory;
+ }
+
+ static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Intent intent, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor, ActivityStack stack) {
+ return getTaskFactory().create(
+ service, taskId, info, intent, voiceSession, voiceInteractor, stack);
+ }
+
+ static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+ return getTaskFactory().create(service, taskId, info, intent, taskDescription, stack);
+ }
+
+ static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ throws IOException, XmlPullParserException {
+ return getTaskFactory().restoreFromXml(in, stackSupervisor);
+ }
+
+ /**
+ * A factory class used to create {@link Task} or its subclass if any. This can be
+ * specified when system boots by setting it with
+ * {@link #setTaskFactory(TaskFactory)}.
+ */
+ static class TaskFactory {
+
+ Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Intent intent, IVoiceInteractionSession voiceSession,
+ IVoiceInteractor voiceInteractor, ActivityStack stack) {
+ return new Task(service, taskId, info, intent, voiceSession, voiceInteractor,
+ null /*taskDescription*/, stack);
+ }
+
+ Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+ return new Task(service, taskId, info, intent, null /*voiceSession*/,
+ null /*voiceInteractor*/, taskDescription, stack);
+ }
+
+ /**
+ * Should only be used when we're restoring {@link Task} from storage.
+ */
+ Task create(ActivityTaskManagerService service, int taskId, Intent intent,
+ Intent affinityIntent, String affinity, String rootAffinity,
+ ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
+ boolean autoRemoveRecents, boolean askedCompatMode, int userId,
+ int effectiveUid, String lastDescription,
+ long lastTimeMoved, boolean neverRelinquishIdentity,
+ TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
+ int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+ int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
+ boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
+ return new Task(service, taskId, intent, affinityIntent, affinity,
+ rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
+ askedCompatMode, userId, effectiveUid, lastDescription,
+ lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
+ prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
+ resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
+ minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
+ null /*_voiceInteractor*/, stack);
+ }
+
+ Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ throws IOException, XmlPullParserException {
+ Intent intent = null;
+ Intent affinityIntent = null;
+ ArrayList<ActivityRecord> activities = new ArrayList<>();
+ ComponentName realActivity = null;
+ boolean realActivitySuspended = false;
+ ComponentName origActivity = null;
+ String affinity = null;
+ String rootAffinity = null;
+ boolean hasRootAffinity = false;
+ boolean rootHasReset = false;
+ boolean autoRemoveRecents = false;
+ boolean askedCompatMode = false;
+ int taskType = 0;
+ int userId = 0;
+ boolean userSetupComplete = true;
+ int effectiveUid = -1;
+ String lastDescription = null;
+ long lastTimeOnTop = 0;
+ boolean neverRelinquishIdentity = true;
+ int taskId = INVALID_TASK_ID;
+ final int outerDepth = in.getDepth();
+ TaskDescription taskDescription = new TaskDescription();
+ int taskAffiliation = INVALID_TASK_ID;
+ int taskAffiliationColor = 0;
+ int prevTaskId = INVALID_TASK_ID;
+ int nextTaskId = INVALID_TASK_ID;
+ int callingUid = -1;
+ String callingPackage = "";
+ int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+ boolean supportsPictureInPicture = false;
+ Rect lastNonFullscreenBounds = null;
+ int minWidth = INVALID_MIN_SIZE;
+ int minHeight = INVALID_MIN_SIZE;
+ int persistTaskVersion = 0;
+
+ for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+ final String attrName = in.getAttributeName(attrNdx);
+ final String attrValue = in.getAttributeValue(attrNdx);
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
+ + attrName + " value=" + attrValue);
+ switch (attrName) {
+ case ATTR_TASKID:
+ if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_REALACTIVITY:
+ realActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_REALACTIVITY_SUSPENDED:
+ realActivitySuspended = Boolean.valueOf(attrValue);
+ break;
+ case ATTR_ORIGACTIVITY:
+ origActivity = ComponentName.unflattenFromString(attrValue);
+ break;
+ case ATTR_AFFINITY:
+ affinity = attrValue;
+ break;
+ case ATTR_ROOT_AFFINITY:
+ rootAffinity = attrValue;
+ hasRootAffinity = true;
+ break;
+ case ATTR_ROOTHASRESET:
+ rootHasReset = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_AUTOREMOVERECENTS:
+ autoRemoveRecents = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_ASKEDCOMPATMODE:
+ askedCompatMode = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_USERID:
+ userId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_USER_SETUP_COMPLETE:
+ userSetupComplete = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_EFFECTIVE_UID:
+ effectiveUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASKTYPE:
+ taskType = Integer.parseInt(attrValue);
+ break;
+ case ATTR_LASTDESCRIPTION:
+ lastDescription = attrValue;
+ break;
+ case ATTR_LASTTIMEMOVED:
+ lastTimeOnTop = Long.parseLong(attrValue);
+ break;
+ case ATTR_NEVERRELINQUISH:
+ neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION:
+ taskAffiliation = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PREV_AFFILIATION:
+ prevTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_NEXT_AFFILIATION:
+ nextTaskId = Integer.parseInt(attrValue);
+ break;
+ case ATTR_TASK_AFFILIATION_COLOR:
+ taskAffiliationColor = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_UID:
+ callingUid = Integer.parseInt(attrValue);
+ break;
+ case ATTR_CALLING_PACKAGE:
+ callingPackage = attrValue;
+ break;
+ case ATTR_RESIZE_MODE:
+ resizeMode = Integer.parseInt(attrValue);
+ break;
+ case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
+ supportsPictureInPicture = Boolean.parseBoolean(attrValue);
+ break;
+ case ATTR_NON_FULLSCREEN_BOUNDS:
+ lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
+ break;
+ case ATTR_MIN_WIDTH:
+ minWidth = Integer.parseInt(attrValue);
+ break;
+ case ATTR_MIN_HEIGHT:
+ minHeight = Integer.parseInt(attrValue);
+ break;
+ case ATTR_PERSIST_TASK_VERSION:
+ persistTaskVersion = Integer.parseInt(attrValue);
+ break;
+ default:
+ if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
+ taskDescription.restoreFromXml(attrName, attrValue);
+ } else {
+ Slog.w(TAG, "Task: Unknown attribute=" + attrName);
+ }
+ }
+ }
+
+ int event;
+ while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
+ && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
+ if (event == XmlPullParser.START_TAG) {
+ final String name = in.getName();
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+ "Task: START_TAG name=" + name);
+ if (TAG_AFFINITYINTENT.equals(name)) {
+ affinityIntent = Intent.restoreFromXml(in);
+ } else if (TAG_INTENT.equals(name)) {
+ intent = Intent.restoreFromXml(in);
+ } else if (TAG_ACTIVITY.equals(name)) {
+ ActivityRecord activity =
+ ActivityRecord.restoreFromXml(in, stackSupervisor);
+ if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
+ + activity);
+ if (activity != null) {
+ activities.add(activity);
+ }
+ } else {
+ handleUnknownTag(name, in);
+ }
+ }
+ }
+ if (!hasRootAffinity) {
+ rootAffinity = affinity;
+ } else if ("@".equals(rootAffinity)) {
+ rootAffinity = null;
+ }
+ if (effectiveUid <= 0) {
+ Intent checkIntent = intent != null ? intent : affinityIntent;
+ effectiveUid = 0;
+ if (checkIntent != null) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(
+ checkIntent.getComponent().getPackageName(),
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ if (ai != null) {
+ effectiveUid = ai.uid;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
+ + ": effectiveUid=" + effectiveUid);
+ }
+
+ if (persistTaskVersion < 1) {
+ // We need to convert the resize mode of home activities saved before version one if
+ // they are marked as RESIZE_MODE_RESIZEABLE to
+ // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
+ // before version 1 and the system didn't resize home activities before then.
+ if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
+ resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+ }
+ } else {
+ // This activity has previously marked itself explicitly as both resizeable and
+ // supporting picture-in-picture. Since there is no longer a requirement for
+ // picture-in-picture activities to be resizeable, we can mark this simply as
+ // resizeable and supporting picture-in-picture separately.
+ if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
+ resizeMode = RESIZE_MODE_RESIZEABLE;
+ supportsPictureInPicture = true;
+ }
+ }
+
+ final Task task = create(stackSupervisor.mService,
+ taskId, intent, affinityIntent,
+ affinity, rootAffinity, realActivity, origActivity, rootHasReset,
+ autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
+ lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+ taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
+ callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
+ userSetupComplete, minWidth, minHeight, null /*stack*/);
+ task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
+ task.setBounds(lastNonFullscreenBounds);
+
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ task.addChild(activities.get(activityNdx));
+ }
+
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
+ return task;
+ }
+
+ void handleUnknownTag(String name, XmlPullParser in)
+ throws IOException, XmlPullParserException {
+ Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+ XmlUtils.skipCurrentTag(in);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index a61c908e0f6f..688fe1290b18 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -350,7 +350,7 @@ class TaskChangeNotificationController {
void notifyActivityPinned(ActivityRecord r) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
- r.getTaskRecord().mTaskId, r.getStackId(), r.packageName);
+ r.getTask().mTaskId, r.getStackId(), r.packageName);
msg.sendingUid = r.mUserId;
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 31145deb449e..d7bc072dc69a 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -93,7 +93,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
}
@VisibleForTesting
- int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout, ActivityRecord activity,
+ int onCalculate(Task task, ActivityInfo.WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
LaunchParams outParams) {
return onCalculate(task, layout, activity, source, options, PHASE_BOUNDS, currentParams,
@@ -101,7 +101,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
}
@Override
- public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ public int onCalculate(Task task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options,
int phase, LaunchParams currentParams, LaunchParams outParams) {
initLogBuilder(task, activity);
@@ -111,7 +111,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
return result;
}
- private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ private int calculate(Task task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options, int phase,
LaunchParams currentParams, LaunchParams outParams) {
final ActivityRecord root;
@@ -292,7 +292,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
return RESULT_CONTINUE;
}
- private int getPreferredLaunchDisplay(@Nullable TaskRecord task,
+ private int getPreferredLaunchDisplay(@Nullable Task task,
@Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
if (!mSupervisor.mService.mSupportsMultiDisplay) {
return DEFAULT_DISPLAY;
@@ -865,7 +865,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
inOutBounds.offset(horizontalOffset, verticalOffset);
}
- private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+ private void initLogBuilder(Task task, ActivityRecord activity) {
if (DEBUG) {
mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
+ " activity=" + activity);
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index f9a75d3d4943..1e2f0d094944 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -118,7 +118,7 @@ public class TaskPersister implements PersisterQueue.Listener {
mPersisterQueue.addListener(this);
}
- private void removeThumbnails(TaskRecord task) {
+ private void removeThumbnails(Task task) {
mPersisterQueue.removeItems(
item -> {
File file = new File(item.mFilePath);
@@ -185,7 +185,7 @@ public class TaskPersister implements PersisterQueue.Listener {
mTaskIdsInFile.delete(userId);
}
- void wakeup(TaskRecord task, boolean flush) {
+ void wakeup(Task task, boolean flush) {
synchronized (mPersisterQueue) {
if (task != null) {
final TaskWriteQueueItem item = mPersisterQueue.findLastItem(
@@ -256,12 +256,12 @@ public class TaskPersister implements PersisterQueue.Listener {
}
}
- private TaskRecord taskIdToTask(int taskId, ArrayList<TaskRecord> tasks) {
+ private Task taskIdToTask(int taskId, ArrayList<Task> tasks) {
if (taskId < 0) {
return null;
}
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
+ final Task task = tasks.get(taskNdx);
if (task.mTaskId == taskId) {
return task;
}
@@ -270,8 +270,8 @@ public class TaskPersister implements PersisterQueue.Listener {
return null;
}
- List<TaskRecord> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
- final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
+ List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
+ final ArrayList<Task> tasks = new ArrayList<Task>();
ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
File userTasksDir = getUserTasksDir(userId);
@@ -320,7 +320,7 @@ public class TaskPersister implements PersisterQueue.Listener {
if (event == XmlPullParser.START_TAG) {
if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);
if (TAG_TASK.equals(name)) {
- final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
+ final Task task = Task.restoreFromXml(in, mStackSupervisor);
if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task="
+ task);
if (task != null) {
@@ -375,14 +375,14 @@ public class TaskPersister implements PersisterQueue.Listener {
// Fix up task affiliation from taskIds
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
+ final Task task = tasks.get(taskNdx);
task.setPrevAffiliate(taskIdToTask(task.mPrevAffiliateTaskId, tasks));
task.setNextAffiliate(taskIdToTask(task.mNextAffiliateTaskId, tasks));
}
- Collections.sort(tasks, new Comparator<TaskRecord>() {
+ Collections.sort(tasks, new Comparator<Task>() {
@Override
- public int compare(TaskRecord lhs, TaskRecord rhs) {
+ public int compare(Task lhs, Task rhs) {
final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
if (diff < 0) {
return -1;
@@ -507,14 +507,14 @@ public class TaskPersister implements PersisterQueue.Listener {
private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
private final ActivityTaskManagerService mService;
- private final TaskRecord mTask;
+ private final Task mTask;
- TaskWriteQueueItem(TaskRecord task, ActivityTaskManagerService service) {
+ TaskWriteQueueItem(Task task, ActivityTaskManagerService service) {
mTask = task;
mService = service;
}
- private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
+ private StringWriter saveToXml(Task task) throws IOException, XmlPullParserException {
if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
final XmlSerializer xmlSerializer = new FastXmlSerializer();
StringWriter stringWriter = new StringWriter();
@@ -542,7 +542,7 @@ public class TaskPersister implements PersisterQueue.Listener {
public void process() {
// Write out one task.
StringWriter stringWriter = null;
- TaskRecord task = mTask;
+ Task task = mTask;
if (DEBUG) Slog.d(TAG, "Writing task=" + task);
synchronized (mService.mGlobalLock) {
if (task.inRecents) {
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
deleted file mode 100644
index d645d72d6075..000000000000
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ /dev/null
@@ -1,2762 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.server.EventLogTags.WM_TASK_REMOVED;
-import static com.android.server.am.TaskRecordProto.ACTIVITIES;
-import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
-import static com.android.server.am.TaskRecordProto.BOUNDS;
-import static com.android.server.am.TaskRecordProto.FULLSCREEN;
-import static com.android.server.am.TaskRecordProto.ID;
-import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
-import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
-import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
-import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
-import static com.android.server.am.TaskRecordProto.STACK_ID;
-import static com.android.server.am.TaskRecordProto.TASK;
-import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
-import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
-import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-
-import static java.lang.Integer.MAX_VALUE;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.AppGlobals;
-import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Debug;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.voice.IVoiceInteractionSession;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.Display;
-import android.view.DisplayInfo;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.util.XmlUtils;
-import com.android.server.protolog.common.ProtoLog;
-import com.android.server.wm.ActivityStack.ActivityState;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Objects;
-
-class TaskRecord extends Task {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
- private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
- private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
- private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
- private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
-
- private static final String ATTR_TASKID = "task_id";
- private static final String TAG_INTENT = "intent";
- private static final String TAG_AFFINITYINTENT = "affinity_intent";
- private static final String ATTR_REALACTIVITY = "real_activity";
- private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
- private static final String ATTR_ORIGACTIVITY = "orig_activity";
- private static final String TAG_ACTIVITY = "activity";
- private static final String ATTR_AFFINITY = "affinity";
- private static final String ATTR_ROOT_AFFINITY = "root_affinity";
- private static final String ATTR_ROOTHASRESET = "root_has_reset";
- private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
- private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
- private static final String ATTR_USERID = "user_id";
- private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
- private static final String ATTR_EFFECTIVE_UID = "effective_uid";
- @Deprecated
- private static final String ATTR_TASKTYPE = "task_type";
- private static final String ATTR_LASTDESCRIPTION = "last_description";
- private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
- private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
- private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
- private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
- private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
- private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
- private static final String ATTR_CALLING_UID = "calling_uid";
- private static final String ATTR_CALLING_PACKAGE = "calling_package";
- private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
- private static final String ATTR_RESIZE_MODE = "resize_mode";
- private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
- private static final String ATTR_MIN_WIDTH = "min_width";
- private static final String ATTR_MIN_HEIGHT = "min_height";
- private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
-
- // Current version of the task record we persist. Used to check if we need to run any upgrade
- // code.
- private static final int PERSIST_TASK_VERSION = 1;
-
- private static final int INVALID_MIN_SIZE = -1;
-
- /**
- * The modes to control how the stack is moved to the front when calling
- * {@link TaskRecord#reparent}.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- REPARENT_MOVE_STACK_TO_FRONT,
- REPARENT_KEEP_STACK_AT_FRONT,
- REPARENT_LEAVE_STACK_IN_PLACE
- })
- @interface ReparentMoveStackMode {}
- // Moves the stack to the front if it was not at the front
- static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
- // Only moves the stack to the front if it was focused or front most already
- static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
- // Do not move the stack as a part of reparenting
- static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
-
- /**
- * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}.
- */
- private static TaskRecordFactory sTaskRecordFactory;
-
- String affinity; // The affinity name for this task, or null; may change identity.
- String rootAffinity; // Initial base affinity, or null; does not change from initial root.
- final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
- final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
- Intent intent; // The original intent that started the task. Note that this value can
- // be null.
- Intent affinityIntent; // Intent of affinity-moved activity that started this task.
- int effectiveUid; // The current effective uid of the identity of this task.
- ComponentName origActivity; // The non-alias activity component of the intent.
- ComponentName realActivity; // The actual activity component that started the task.
- boolean realActivitySuspended; // True if the actual activity component that started the
- // task is suspended.
- boolean inRecents; // Actually in the recents list?
- long lastActiveTime; // Last time this task was active in the current device session,
- // including sleep. This time is initialized to the elapsed time when
- // restored from disk.
- boolean isAvailable; // Is the activity available to be launched?
- boolean rootWasReset; // True if the intent at the root of the task had
- // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
- boolean autoRemoveRecents; // If true, we should automatically remove the task from
- // recents when activity finishes
- boolean askedCompatMode;// Have asked the user about compat mode for this task.
- boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
-
- String stringName; // caching of toString() result.
- boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
- // was changed.
-
- int numFullscreen; // Number of fullscreen activities.
-
- /** Can't be put in lockTask mode. */
- final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
- /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_PINNABLE = 1;
- /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
- /** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_WHITELISTED = 3;
- /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
- * lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
- int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
-
- int mLockTaskUid = -1; // The uid of the application that called startLockTask().
-
- /** Current stack. Setter must always be used to update the value. */
- private ActivityStack mStack;
-
- /** The process that had previously hosted the root activity of this task.
- * Used to know that we should try harder to keep this process around, in case the
- * user wants to return to it. */
- private WindowProcessController mRootProcess;
-
- /** Takes on same value as first root activity */
- boolean isPersistable = false;
- int maxRecents;
-
- /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
- * determining the order when restoring. Sign indicates whether last task movement was to front
- * (positive) or back (negative). Absolute value indicates time. */
- long mLastTimeMoved;
-
- /** If original intent did not allow relinquishing task identity, save that information */
- private boolean mNeverRelinquishIdentity = true;
-
- // Used in the unique case where we are clearing the task in order to reuse it. In that case we
- // do not want to delete the stack when the task goes empty.
- private boolean mReuseTask = false;
-
- CharSequence lastDescription; // Last description captured for this item.
-
- int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
- int mAffiliatedTaskColor; // color of the parent task affiliation.
- TaskRecord mPrevAffiliate; // previous task in affiliated chain.
- int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
- TaskRecord mNextAffiliate; // next task in affiliated chain.
- int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
-
- // For relaunching the task from recents as though it was launched by the original launcher.
- int mCallingUid;
- String mCallingPackage;
-
- private final Rect mTmpStableBounds = new Rect();
- private final Rect mTmpNonDecorBounds = new Rect();
- private final Rect mTmpBounds = new Rect();
- private final Rect mTmpInsets = new Rect();
-
- // Last non-fullscreen bounds the task was launched in or resized to.
- // The information is persisted and used to determine the appropriate stack to launch the
- // task into on restore.
- Rect mLastNonFullscreenBounds = null;
- // Minimal width and height of this task when it's resizeable. -1 means it should use the
- // default minimal width/height.
- int mMinWidth;
- int mMinHeight;
-
- // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
- // This number will be assigned when we evaluate OOM scores for all visible tasks.
- int mLayerRank = -1;
-
- /** Helper object used for updating override configuration. */
- private Configuration mTmpConfig = new Configuration();
-
- /** Used by fillTaskInfo */
- final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
-
- /**
- * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
- * ActivityInfo, Intent, TaskDescription)} instead.
- */
- TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- TaskDescription _taskDescription, ActivityStack stack) {
- this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
- null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
- false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
- UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
- null /*_lastDescription*/, System.currentTimeMillis(),
- true /*neverRelinquishIdentity*/,
- _taskDescription != null ? _taskDescription : new TaskDescription(),
- _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
- info.applicationInfo.uid, info.packageName, info.resizeMode,
- info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
- false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
- _voiceSession, _voiceInteractor, stack);
- }
-
- /** Don't use constructor directly. This is only used by XML parser. */
- TaskRecord(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
- Intent _affinityIntent, String _affinity, String _rootAffinity,
- ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
- boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
- int _effectiveUid, String _lastDescription,
- long lastTimeMoved, boolean neverRelinquishIdentity,
- TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
- int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- ActivityStack stack) {
- super(_taskId, stack, _userId, resizeMode,
- supportsPictureInPicture, _lastTaskDescription, atmService);
- mRemoteToken = new RemoteToken(this);
- affinityIntent = _affinityIntent;
- affinity = _affinity;
- rootAffinity = _rootAffinity;
- voiceSession = _voiceSession;
- voiceInteractor = _voiceInteractor;
- realActivity = _realActivity;
- realActivitySuspended = _realActivitySuspended;
- origActivity = _origActivity;
- rootWasReset = _rootWasReset;
- isAvailable = true;
- autoRemoveRecents = _autoRemoveRecents;
- askedCompatMode = _askedCompatMode;
- mUserSetupComplete = userSetupComplete;
- effectiveUid = _effectiveUid;
- touchActiveTime();
- lastDescription = _lastDescription;
- mLastTimeMoved = lastTimeMoved;
- mNeverRelinquishIdentity = neverRelinquishIdentity;
- mAffiliatedTaskId = taskAffiliation;
- mAffiliatedTaskColor = taskAffiliationColor;
- mPrevAffiliateTaskId = prevTaskId;
- mNextAffiliateTaskId = nextTaskId;
- mCallingUid = callingUid;
- mCallingPackage = callingPackage;
- mResizeMode = resizeMode;
- if (info != null) {
- setIntent(_intent, info);
- setMinDimensions(info);
- } else {
- intent = _intent;
- mMinWidth = minWidth;
- mMinHeight = minHeight;
- }
- mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
- }
-
- void cleanUpResourcesForDestroy() {
- if (hasChild()) {
- return;
- }
-
- // This task is going away, so save the last state if necessary.
- saveLaunchingStateIfNeeded();
-
- // TODO: VI what about activity?
- final boolean isVoiceSession = voiceSession != null;
- if (isVoiceSession) {
- try {
- voiceSession.taskFinished(intent, mTaskId);
- } catch (RemoteException e) {
- }
- }
- if (autoRemoveFromRecents() || isVoiceSession) {
- // Task creator asked to remove this when done, or this task was a voice
- // interaction, so it should not remain on the recent tasks list.
- mAtmService.mStackSupervisor.mRecentTasks.remove(this);
- }
-
- removeIfPossible();
- }
-
- @VisibleForTesting
- @Override
- void removeIfPossible() {
- mAtmService.getLockTaskController().clearLockedTask(this);
- super.removeIfPossible();
- mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
- }
-
- void setResizeMode(int resizeMode) {
- if (mResizeMode == resizeMode) {
- return;
- }
- mResizeMode = resizeMode;
- mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
- updateTaskDescription();
- }
-
- boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
- mAtmService.deferWindowLayout();
-
- try {
- final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-
- if (getParent() == null) {
- // Task doesn't exist in window manager yet (e.g. was restored from recents).
- // All we can do for now is update the bounds so it can be used when the task is
- // added to window manager.
- setBounds(bounds);
- if (!inFreeformWindowingMode()) {
- // re-restore the task so it can have the proper stack association.
- mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
- }
- return true;
- }
-
- if (!canResizeToBounds(bounds)) {
- throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
- + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
- }
-
- // Do not move the task to another stack here.
- // This method assumes that the task is already placed in the right stack.
- // we do not mess with that decision and we only do the resize!
-
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
-
- boolean updatedConfig = false;
- mTmpConfig.setTo(getResolvedOverrideConfiguration());
- if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
- updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
- }
- // This variable holds information whether the configuration didn't change in a significant
-
- // way and the activity was kept the way it was. If it's false, it means the activity
- // had
- // to be relaunched due to configuration change.
- boolean kept = true;
- if (updatedConfig) {
- final ActivityRecord r = topRunningActivityLocked();
- if (r != null && !deferResume) {
- kept = r.ensureActivityConfiguration(0 /* globalChanges */,
- preserveWindow);
- // Preserve other windows for resizing because if resizing happens when there
- // is a dialog activity in the front, the activity that still shows some
- // content to the user will become black and cause flickers. Note in most cases
- // this won't cause tons of irrelevant windows being preserved because only
- // activities in this task may experience a bounds change. Configs for other
- // activities stay the same.
- mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow);
- if (!kept) {
- mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
- }
- }
- }
- resize(kept, forced);
-
- saveLaunchingStateIfNeeded();
-
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- return kept;
- } finally {
- mAtmService.continueWindowLayout();
- }
- }
-
- /**
- * Convenience method to reparent a task to the top or bottom position of the stack.
- */
- boolean reparent(ActivityStack preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
- String reason) {
- return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
- true /* schedulePictureInPictureModeChange */, reason);
- }
-
- /**
- * Convenience method to reparent a task to the top or bottom position of the stack, with
- * an option to skip scheduling the picture-in-picture mode change.
- */
- boolean reparent(ActivityStack preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
- boolean schedulePictureInPictureModeChange, String reason) {
- return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
- deferResume, schedulePictureInPictureModeChange, reason);
- }
-
- /** Convenience method to reparent a task to a specific position of the stack. */
- boolean reparent(ActivityStack preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
- String reason) {
- return reparent(preferredStack, position, moveStackMode, animate, deferResume,
- true /* schedulePictureInPictureModeChange */, reason);
- }
-
- /**
- * Reparents the task into a preferred stack, creating it if necessary.
- *
- * @param preferredStack the target stack to move this task
- * @param position the position to place this task in the new stack
- * @param animate whether or not we should wait for the new window created as a part of the
- * reparenting to be drawn and animated in
- * @param moveStackMode whether or not to move the stack to the front always, only if it was
- * previously focused & in front, or never
- * @param deferResume whether or not to update the visibility of other tasks and stacks that may
- * have changed as a result of this reparenting
- * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
- * change. Callers may set this to false if they are explicitly scheduling PiP mode
- * changes themselves, like during the PiP animation
- * @param reason the caller of this reparenting
- * @return whether the task was reparented
- */
- // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
- // re-parenting the task. Can only be done when we are no longer using static stack Ids.
- boolean reparent(ActivityStack preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
- boolean schedulePictureInPictureModeChange, String reason) {
- final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
- final RootActivityContainer root = mAtmService.mRootActivityContainer;
- final WindowManagerService windowManager = mAtmService.mWindowManager;
- final ActivityStack sourceStack = getStack();
- final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
- position == MAX_VALUE);
- if (toStack == sourceStack) {
- return false;
- }
- if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
- return false;
- }
-
- final boolean toTopOfStack = position == MAX_VALUE;
- if (toTopOfStack && toStack.getResumedActivity() != null
- && toStack.topRunningActivityLocked() != null) {
- // Pause the resumed activity on the target stack while re-parenting task on top of it.
- toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
- null /* resuming */);
- }
-
- final int toStackWindowingMode = toStack.getWindowingMode();
- final ActivityRecord topActivity = getTopActivity();
-
- final boolean mightReplaceWindow = topActivity != null
- && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
- if (mightReplaceWindow) {
- // We are about to relaunch the activity because its configuration changed due to
- // being maximized, i.e. size change. The activity will first remove the old window
- // and then add a new one. This call will tell window manager about this, so it can
- // preserve the old window until the new one is drawn. This prevents having a gap
- // between the removal and addition, in which no window is visible. We also want the
- // entrance of the new window to be properly animated.
- // Note here we always set the replacing window first, as the flags might be needed
- // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
- windowManager.setWillReplaceWindow(topActivity.appToken, animate);
- }
-
- mAtmService.deferWindowLayout();
- boolean kept = true;
- try {
- final ActivityRecord r = topRunningActivityLocked();
- // give pinned stack a chance to save current bounds, this needs to be before the
- // actual reparent.
- if (inPinnedWindowingMode()
- && !(toStackWindowingMode == WINDOWING_MODE_UNDEFINED)
- && !r.isHidden()) {
- r.savePinnedStackBounds();
- }
- final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
- && (topRunningActivityLocked() == r);
- final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
- final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
-
- // In some cases the focused stack isn't the front stack. E.g. pinned stack.
- // Whenever we are moving the top activity from the front stack we want to make sure to
- // move the stack to the front.
- final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
- && (sourceStack.topRunningActivityLocked() == r);
-
- final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
- || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
-
- reparent(toStack, position, moveStackToFront, reason);
-
- if (schedulePictureInPictureModeChange) {
- // Notify of picture-in-picture mode changes
- supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
- }
-
- // If the task had focus before (or we're requested to move focus), move focus to the
- // new stack by moving the stack to the front.
- if (r != null) {
- toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
- wasPaused, reason);
- }
- if (!animate) {
- mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
- }
-
- // We might trigger a configuration change. Save the current task bounds for freezing.
- // TODO: Should this call be moved inside the resize method in WM?
- toStack.prepareFreezingTaskBounds();
-
- // Make sure the task has the appropriate bounds/size for the stack it is in.
- final boolean toStackSplitScreenPrimary =
- toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
- final Rect configBounds = getRequestedOverrideBounds();
- if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
- || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
- && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
- kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
- !mightReplaceWindow, deferResume);
- } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
- Rect bounds = getLaunchBounds();
- if (bounds == null) {
- mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
- bounds = configBounds;
- }
- kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
- } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
- if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
- // Move recents to front so it is not behind home stack when going into docked
- // mode
- mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
- }
- kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
- !mightReplaceWindow, deferResume);
- }
- } finally {
- mAtmService.continueWindowLayout();
- }
-
- if (mightReplaceWindow) {
- // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
- // window), we need to clear the replace window settings. Otherwise, we schedule a
- // timeout to remove the old window if the replacing window is not coming in time.
- windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
- }
-
- if (!deferResume) {
- // The task might have already been running and its visibility needs to be synchronized
- // with the visibility of the stack / windows.
- root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
- root.resumeFocusedStacksTopActivities();
- }
-
- // TODO: Handle incorrect request to move before the actual move, not after.
- supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
- DEFAULT_DISPLAY, toStack);
-
- return (preferredStack == toStack);
- }
-
- /**
- * @return True if the windows of tasks being moved to the target stack from the source stack
- * should be replaced, meaning that window manager will keep the old window around until the new
- * is ready.
- */
- private static boolean replaceWindowsOnTaskMove(
- int sourceWindowingMode, int targetWindowingMode) {
- return sourceWindowingMode == WINDOWING_MODE_FREEFORM
- || targetWindowingMode == WINDOWING_MODE_FREEFORM;
- }
-
- /**
- * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
- */
- TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
-
- // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
- // synchronized between AM and WM.
- return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
- restoreFromDisk);
- }
-
- void touchActiveTime() {
- lastActiveTime = SystemClock.elapsedRealtime();
- }
-
- long getInactiveDuration() {
- return SystemClock.elapsedRealtime() - lastActiveTime;
- }
-
- /** Sets the original intent, and the calling uid and package. */
- void setIntent(ActivityRecord r) {
- mCallingUid = r.launchedFromUid;
- mCallingPackage = r.launchedFromPackage;
- setIntent(r.intent, r.info);
- setLockTaskAuth(r);
- }
-
- /** Sets the original intent, _without_ updating the calling uid or package. */
- private void setIntent(Intent _intent, ActivityInfo info) {
- if (intent == null) {
- mNeverRelinquishIdentity =
- (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
- } else if (mNeverRelinquishIdentity) {
- return;
- }
-
- affinity = info.taskAffinity;
- if (intent == null) {
- // If this task already has an intent associated with it, don't set the root
- // affinity -- we don't want it changing after initially set, but the initially
- // set value may be null.
- rootAffinity = affinity;
- }
- effectiveUid = info.applicationInfo.uid;
- stringName = null;
-
- if (info.targetActivity == null) {
- if (_intent != null) {
- // If this Intent has a selector, we want to clear it for the
- // recent task since it is not relevant if the user later wants
- // to re-launch the app.
- if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
- _intent = new Intent(_intent);
- _intent.setSelector(null);
- _intent.setSourceBounds(null);
- }
- }
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
- intent = _intent;
- realActivity = _intent != null ? _intent.getComponent() : null;
- origActivity = null;
- } else {
- ComponentName targetComponent = new ComponentName(
- info.packageName, info.targetActivity);
- if (_intent != null) {
- Intent targetIntent = new Intent(_intent);
- targetIntent.setSelector(null);
- targetIntent.setSourceBounds(null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Setting Intent of " + this + " to target " + targetIntent);
- intent = targetIntent;
- realActivity = targetComponent;
- origActivity = _intent.getComponent();
- } else {
- intent = null;
- realActivity = targetComponent;
- origActivity = new ComponentName(info.packageName, info.name);
- }
- }
-
- final int intentFlags = intent == null ? 0 : intent.getFlags();
- if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
- // Once we are set to an Intent with this flag, we count this
- // task as having a true root activity.
- rootWasReset = true;
- }
- mUserId = UserHandle.getUserId(info.applicationInfo.uid);
- mUserSetupComplete = Settings.Secure.getIntForUser(
- mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
- if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
- // If the activity itself has requested auto-remove, then just always do it.
- autoRemoveRecents = true;
- } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
- == FLAG_ACTIVITY_NEW_DOCUMENT) {
- // If the caller has not asked for the document to be retained, then we may
- // want to turn on auto-remove, depending on whether the target has set its
- // own document launch mode.
- if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
- autoRemoveRecents = false;
- } else {
- autoRemoveRecents = true;
- }
- } else {
- autoRemoveRecents = false;
- }
- if (mResizeMode != info.resizeMode) {
- mResizeMode = info.resizeMode;
- updateTaskDescription();
- }
- mSupportsPictureInPicture = info.supportsPictureInPicture();
- }
-
- /** Sets the original minimal width and height. */
- private void setMinDimensions(ActivityInfo info) {
- if (info != null && info.windowLayout != null) {
- mMinWidth = info.windowLayout.minWidth;
- mMinHeight = info.windowLayout.minHeight;
- } else {
- mMinWidth = INVALID_MIN_SIZE;
- mMinHeight = INVALID_MIN_SIZE;
- }
- }
-
- /**
- * Return true if the input activity has the same intent filter as the intent this task
- * record is based on (normally the root activity intent).
- */
- boolean isSameIntentFilter(ActivityRecord r) {
- final Intent intent = new Intent(r.intent);
- // Make sure the component are the same if the input activity has the same real activity
- // as the one in the task because either one of them could be the alias activity.
- if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
- intent.setComponent(this.intent.getComponent());
- }
- return intent.filterEquals(this.intent);
- }
-
- boolean returnsToHomeStack() {
- final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
- return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
- }
-
- void setPrevAffiliate(TaskRecord prevAffiliate) {
- mPrevAffiliate = prevAffiliate;
- mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
- }
-
- void setNextAffiliate(TaskRecord nextAffiliate) {
- mNextAffiliate = nextAffiliate;
- mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
- }
-
- ActivityStack getStack() {
- return mStack;
- }
-
- @Override
- void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- // TODO(stack-merge): Remove cats ater object merge.
- final ActivityStack oldStack = ((ActivityStack) oldParent);
- final ActivityStack newStack = ((ActivityStack) newParent);
-
- mStack = newStack;
-
- super.onParentChanged(newParent, oldParent);
-
- if (oldStack != null) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = getChildAt(i);
- oldStack.onActivityRemovedFromStack(activity);
- }
-
- updateTaskMovement(true /*toFront*/);
-
- if (oldStack.inPinnedWindowingMode()
- && (newStack == null || !newStack.inPinnedWindowingMode())) {
- // Notify if a task from the pinned stack is being removed
- // (or moved depending on the mode).
- mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
- }
- }
-
- if (newStack != null) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = getChildAt(i);
- newStack.onActivityAddedToStack(activity);
- }
-
- // TODO: Ensure that this is actually necessary here
- // Notify the voice session if required
- if (voiceSession != null) {
- try {
- voiceSession.taskStarted(intent, mTaskId);
- } catch (RemoteException e) {
- }
- }
- }
-
- // First time we are adding the task to the system.
- if (oldParent == null && newParent != null) {
-
- // TODO: Super random place to be doing this, but aligns with what used to be done
- // before we unified Task level. Look into if this can be done in a better place.
- updateOverrideConfigurationFromLaunchBounds();
- }
-
- // Task is being removed.
- if (oldParent != null && newParent == null) {
- cleanUpResourcesForDestroy();
- }
-
-
- // Update task bounds if needed.
- adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
-
- if (getWindowConfiguration().windowsAreScaleable()) {
- // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
- // while a resize is pending.
- forceWindowsScaleable(true /* force */);
- } else {
- forceWindowsScaleable(false /* force */);
- }
-
- mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
- }
-
- /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */
- void updateTaskMovement(boolean toFront) {
- if (isPersistable) {
- mLastTimeMoved = System.currentTimeMillis();
- // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
- // recently will be most negative, tasks sent to the bottom before that will be less
- // negative. Similarly for recent tasks moved to the top which will be most positive.
- if (!toFront) {
- mLastTimeMoved *= -1;
- }
- }
- mAtmService.mRootActivityContainer.invalidateTaskLayers();
- }
-
- /**
- * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
- */
- int getStackId() {
- return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
- }
-
- // Close up recents linked list.
- private void closeRecentsChain() {
- if (mPrevAffiliate != null) {
- mPrevAffiliate.setNextAffiliate(mNextAffiliate);
- }
- if (mNextAffiliate != null) {
- mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
- }
- setPrevAffiliate(null);
- setNextAffiliate(null);
- }
-
- void removedFromRecents() {
- closeRecentsChain();
- if (inRecents) {
- inRecents = false;
- mAtmService.notifyTaskPersisterLocked(this, false);
- }
-
- clearRootProcess();
-
- mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
- mTaskId, mUserId);
- }
-
- void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
- closeRecentsChain();
- mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
- mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
- // Find the end
- while (taskToAffiliateWith.mNextAffiliate != null) {
- final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
- if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
- Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
- + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
- if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
- nextRecents.setPrevAffiliate(null);
- }
- taskToAffiliateWith.setNextAffiliate(null);
- break;
- }
- taskToAffiliateWith = nextRecents;
- }
- taskToAffiliateWith.setNextAffiliate(this);
- setPrevAffiliate(taskToAffiliateWith);
- setNextAffiliate(null);
- }
-
- /** Returns the intent for the root activity for this task */
- Intent getBaseIntent() {
- return intent != null ? intent : affinityIntent;
- }
-
- /** Returns the first non-finishing activity from the bottom. */
- ActivityRecord getRootActivity() {
- final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
- if (rootActivityIndex == -1) {
- // There are no non-finishing activities in the task.
- return null;
- }
- return getChildAt(rootActivityIndex);
- }
-
- ActivityRecord getTopActivity() {
- return getTopActivity(true /* includeOverlays */);
- }
-
- ActivityRecord getTopActivity(boolean includeOverlays) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
- continue;
- }
- return r;
- }
- return null;
- }
-
- ActivityRecord topRunningActivityLocked() {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (!r.finishing && r.okToShowLocked()) {
- return r;
- }
- }
- }
- return null;
- }
-
- /**
- * Return true if any activities in this task belongs to input uid.
- */
- boolean containsAppUid(int uid) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.getUid() == uid) {
- return true;
- }
- }
- return false;
- }
-
- void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
- outActivities.add(r);
- }
- }
- }
- }
-
- ActivityRecord topRunningActivityWithStartingWindowLocked() {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
- || r.finishing || !r.okToShowLocked()) {
- continue;
- }
- return r;
- }
- }
- return null;
- }
-
- /**
- * Return the number of running activities, and the number of non-finishing/initializing
- * activities in the provided {@param reportOut} respectively.
- */
- void getNumRunningActivities(TaskActivitiesReport reportOut) {
- reportOut.reset();
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.finishing) {
- continue;
- }
-
- reportOut.base = r;
-
- // Increment the total number of non-finishing activities
- reportOut.numActivities++;
-
- if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
- reportOut.top = r;
- // Reset the number of running activities until we hit the first non-initializing
- // activity
- reportOut.numRunning = 0;
- }
- if (r.attachedToProcess()) {
- // Increment the number of actually running activities
- reportOut.numRunning++;
- }
- }
- }
-
- boolean okToShowLocked() {
- // NOTE: If {@link TaskRecord#topRunningActivity} return is not null then it is
- // okay to show the activity when locked.
- return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
- || topRunningActivityLocked() != null;
- }
-
- /**
- * Reorder the history stack so that the passed activity is brought to the front.
- */
- final void moveActivityToFrontLocked(ActivityRecord newTop) {
- if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
- + newTop + " to stack at top callers=" + Debug.getCallers(4));
-
- positionChildAtTop(newTop);
- updateEffectiveIntent();
- }
-
- @Override
- /*@WindowConfiguration.ActivityType*/
- public int getActivityType() {
- final int applicationType = super.getActivityType();
- if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
- return applicationType;
- }
- return getChildAt(0).getActivityType();
- }
-
- @Override
- void addChild(ActivityRecord r, int index) {
- // If this task had any child before we added this one.
- boolean hadChild = hasChild();
-
- index = getAdjustedAddPosition(r, index);
- super.addChild(r, index);
-
- ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
- r.inHistory = true;
-
- if (r.occludesParent()) {
- numFullscreen++;
- }
- // Only set this based on the first activity
- if (!hadChild) {
- if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
- // Normally non-standard activity type for the activity record will be set when the
- // object is created, however we delay setting the standard application type until
- // this point so that the task can set the type for additional activities added in
- // the else condition below.
- r.setActivityType(ACTIVITY_TYPE_STANDARD);
- }
- setActivityType(r.getActivityType());
- isPersistable = r.isPersistable();
- mCallingUid = r.launchedFromUid;
- mCallingPackage = r.launchedFromPackage;
- // Clamp to [1, max].
- maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
- ActivityTaskManager.getMaxAppRecentsLimitStatic());
- } else {
- // Otherwise make all added activities match this one.
- r.setActivityType(getActivityType());
- }
-
- updateEffectiveIntent();
- if (r.isPersistable()) {
- mAtmService.notifyTaskPersisterLocked(this, false);
- }
-
- // Make sure the list of display UID whitelists is updated
- // now that this record is in a new task.
- mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
- }
-
- void addChild(ActivityRecord r) {
- addChild(r, Integer.MAX_VALUE /* add on top */);
- }
-
- @Override
- void removeChild(ActivityRecord r) {
- if (!mChildren.contains(r)) {
- Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
- return;
- }
-
- super.removeChild(r);
- if (r.occludesParent()) {
- numFullscreen--;
- }
- if (r.isPersistable()) {
- mAtmService.notifyTaskPersisterLocked(this, false);
- }
-
- if (inPinnedWindowingMode()) {
- // We normally notify listeners of task stack changes on pause, however pinned stack
- // activities are normally in the paused state so no notification will be sent there
- // before the activity is removed. We send it here so instead.
- mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
- }
-
- final String reason = "removeChild";
- if (hasChild()) {
- updateEffectiveIntent();
-
- // The following block can be executed multiple times if there is more than one overlay.
- // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
- // of the task by id and exiting early if not found.
- if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
- // When destroying a task, tell the supervisor to remove it so that any activity it
- // has can be cleaned up correctly. This is currently the only place where we remove
- // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
- // state into removeChild(), we just clear the task here before the other residual
- // work.
- // TODO: If the callers to removeChild() changes such that we have multiple places
- // where we are destroying the task, move this back into removeChild()
- mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
- !REMOVE_FROM_RECENTS, reason);
- }
- } else if (!mReuseTask) {
- // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
- mStack.removeChild(this, reason);
- EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
- "removeChild: last r=" + r + " in t=" + this);
- removeIfPossible();
- }
- }
-
- /**
- * @return whether or not there are ONLY task overlay activities in the stack.
- * If {@param excludeFinishing} is set, then ignore finishing activities in the check.
- * If there are no task overlay activities, this call returns false.
- */
- boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
- int count = 0;
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord r = getChildAt(i);
- if (excludeFinishing && r.finishing) {
- continue;
- }
- if (!r.mTaskOverlay) {
- return false;
- }
- count++;
- }
- return count > 0;
- }
-
- boolean autoRemoveFromRecents() {
- // We will automatically remove the task either if it has explicitly asked for
- // this, or it is empty and has never contained an activity that got shown to
- // the user.
- return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
- }
-
- /**
- * Completely remove all activities associated with an existing
- * task starting at a specified index.
- */
- private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
- int numActivities = getChildCount();
- for ( ; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (mStack == null) {
- // Task was restored from persistent storage.
- r.takeFromHistory();
- removeChild(r);
- --activityNdx;
- --numActivities;
- } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
- false /* oomAdj */)
- == FINISH_RESULT_REMOVED) {
- --activityNdx;
- --numActivities;
- }
- }
- }
-
- /**
- * Completely remove all activities associated with an existing task.
- */
- void performClearTaskLocked() {
- mReuseTask = true;
- performClearTaskAtIndexLocked(0, "clear-task-all");
- mReuseTask = false;
- }
-
- ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
- mReuseTask = true;
- final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
- mReuseTask = false;
- return result;
- }
-
- /**
- * Perform clear operation as requested by
- * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
- * stack to the given task, then look for
- * an instance of that activity in the stack and, if found, finish all
- * activities on top of it and return the instance.
- *
- * @param newR Description of the new activity being started.
- * @return Returns the old activity that should be continued to be used,
- * or null if none was found.
- */
- final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
- int numActivities = getChildCount();
- for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (r.mActivityComponent.equals(newR.mActivityComponent)) {
- // Here it is! Now finish everything in front...
- final ActivityRecord ret = r;
-
- for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
- r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
- if (opts != null) {
- ret.updateOptionsLocked(opts);
- }
- if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
- == FINISH_RESULT_REMOVED) {
- --activityNdx;
- --numActivities;
- }
- }
-
- // Finally, if this is a normal launch mode (that is, not
- // expecting onNewIntent()), then we will finish the current
- // instance of the activity so a new fresh one can be started.
- if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
- && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
- && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
- if (!ret.finishing) {
- ret.finishIfPossible("clear-task-top", false /* oomAdj */);
- return null;
- }
- }
-
- return ret;
- }
- }
-
- return null;
- }
-
- void removeTaskActivitiesLocked(String reason) {
- // Just remove the entire task.
- performClearTaskAtIndexLocked(0, reason);
- }
-
- String lockTaskAuthToString() {
- switch (mLockTaskAuth) {
- case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
- case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
- case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
- case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
- case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
- default: return "unknown=" + mLockTaskAuth;
- }
- }
-
- void setLockTaskAuth() {
- setLockTaskAuth(getRootActivity());
- }
-
- private void setLockTaskAuth(@Nullable ActivityRecord r) {
- if (r == null) {
- mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
- return;
- }
-
- final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
- final LockTaskController lockTaskController = mAtmService.getLockTaskController();
- switch (r.lockTaskLaunchMode) {
- case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_NEVER:
- mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_ALWAYS:
- mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
- break;
- }
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
- " mLockTaskAuth=" + lockTaskAuthToString());
- }
-
- @Override
- public boolean supportsSplitScreenWindowingMode() {
- // A task can not be docked even if it is considered resizeable because it only supports
- // picture-in-picture mode but has a non-resizeable resizeMode
- return super.supportsSplitScreenWindowingMode()
- // TODO(task-group): Probably makes sense to move this and associated code into
- // WindowContainer so it affects every node.
- && mAtmService.mSupportsSplitScreenMultiWindow
- && (mAtmService.mForceResizableActivities
- || (isResizeable(false /* checkSupportsPip */)
- && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
- }
-
- /**
- * Check whether this task can be launched on the specified display.
- *
- * @param displayId Target display id.
- * @return {@code true} if either it is the default display or this activity can be put on a
- * secondary display.
- */
- boolean canBeLaunchedOnDisplay(int displayId) {
- return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
- -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
- }
-
- /**
- * Check that a given bounds matches the application requested orientation.
- *
- * @param bounds The bounds to be tested.
- * @return True if the requested bounds are okay for a resizing request.
- */
- private boolean canResizeToBounds(Rect bounds) {
- if (bounds == null || !inFreeformWindowingMode()) {
- // Note: If not on the freeform workspace, we ignore the bounds.
- return true;
- }
- final boolean landscape = bounds.width() > bounds.height();
- final Rect configBounds = getRequestedOverrideBounds();
- if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
- return configBounds.isEmpty()
- || landscape == (configBounds.width() > configBounds.height());
- }
- return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
- && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
- }
-
- /**
- * @return {@code true} if the task is being cleared for the purposes of being reused.
- */
- boolean isClearingToReuseTask() {
- return mReuseTask;
- }
-
- /**
- * Find the activity in the history stack within the given task. Returns
- * the index within the history at which it's found, or < 0 if not found.
- */
- final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
- final ComponentName realActivity = r.mActivityComponent;
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord candidate = getChildAt(activityNdx);
- if (candidate.finishing) {
- continue;
- }
- if (candidate.mActivityComponent.equals(realActivity)) {
- return candidate;
- }
- }
- return null;
- }
-
- /** Updates the last task description values. */
- void updateTaskDescription() {
- // TODO(AM refactor): Cleanup to use findRootIndex()
- // Traverse upwards looking for any break between main task activities and
- // utility activities.
- int activityNdx;
- final int numActivities = getChildCount();
- final boolean relinquish = numActivities != 0 &&
- (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
- for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
- ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
- // This will be the top activity for determining taskDescription. Pre-inc to
- // overcome initial decrement below.
- ++activityNdx;
- break;
- }
- if (r.intent != null &&
- (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
- break;
- }
- }
- if (activityNdx > 0) {
- // Traverse downwards starting below break looking for set label, icon.
- // Note that if there are activities in the task but none of them set the
- // recent activity values, then we do not fall back to the last set
- // values in the TaskRecord.
- String label = null;
- String iconFilename = null;
- int iconResource = -1;
- int colorPrimary = 0;
- int colorBackground = 0;
- int statusBarColor = 0;
- int navigationBarColor = 0;
- boolean statusBarContrastWhenTransparent = false;
- boolean navigationBarContrastWhenTransparent = false;
- boolean topActivity = true;
- for (--activityNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.mTaskOverlay) {
- continue;
- }
- if (r.taskDescription != null) {
- if (label == null) {
- label = r.taskDescription.getLabel();
- }
- if (iconResource == -1) {
- iconResource = r.taskDescription.getIconResource();
- }
- if (iconFilename == null) {
- iconFilename = r.taskDescription.getIconFilename();
- }
- if (colorPrimary == 0) {
- colorPrimary = r.taskDescription.getPrimaryColor();
- }
- if (topActivity) {
- colorBackground = r.taskDescription.getBackgroundColor();
- statusBarColor = r.taskDescription.getStatusBarColor();
- navigationBarColor = r.taskDescription.getNavigationBarColor();
- statusBarContrastWhenTransparent =
- r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
- navigationBarContrastWhenTransparent =
- r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
- }
- }
- topActivity = false;
- }
- final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
- iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
- statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
- mResizeMode, mMinWidth, mMinHeight);
- setTaskDescription(taskDescription);
- // Update the task affiliation color if we are the parent of the group
- if (mTaskId == mAffiliatedTaskId) {
- mAffiliatedTaskColor = taskDescription.getPrimaryColor();
- }
- mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
- getTaskInfo());
- }
- }
-
- /**
- * Find the index of the root activity in the task. It will be the first activity from the
- * bottom that is not finishing.
- *
- * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
- * activity that defines the task identity (its base intent). It's the
- * first one that does not have
- * {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
- * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
- * activity was found.
- */
- int findRootIndex(boolean effectiveRoot) {
- int effectiveNdx = -1;
- final int topActivityNdx = getChildCount() - 1;
- for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- effectiveNdx = activityNdx;
- if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
- break;
- }
- }
- return effectiveNdx;
- }
-
- // TODO (AM refactor): Invoke automatically when there is a change in children
- @VisibleForTesting
- void updateEffectiveIntent() {
- int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
- if (effectiveRootIndex == -1) {
- // All activities in the task are either finishing or relinquish task identity.
- // But we still want to update the intent, so let's use the bottom activity.
- effectiveRootIndex = 0;
- }
- final ActivityRecord r = getChildAt(effectiveRootIndex);
- setIntent(r);
-
- // Update the task description when the activities change
- updateTaskDescription();
- }
-
- void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
- if (bounds == null) {
- return;
- }
- int minWidth = mMinWidth;
- int minHeight = mMinHeight;
- // If the task has no requested minimal size, we'd like to enforce a minimal size
- // so that the user can not render the task too small to manipulate. We don't need
- // to do this for the pinned stack as the bounds are controlled by the system.
- if (!inPinnedWindowingMode() && mStack != null) {
- final int defaultMinSizeDp =
- mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
- final ActivityDisplay display =
- mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
- final float density =
- (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
- final int defaultMinSize = (int) (defaultMinSizeDp * density);
-
- if (minWidth == INVALID_MIN_SIZE) {
- minWidth = defaultMinSize;
- }
- if (minHeight == INVALID_MIN_SIZE) {
- minHeight = defaultMinSize;
- }
- }
- final boolean adjustWidth = minWidth > bounds.width();
- final boolean adjustHeight = minHeight > bounds.height();
- if (!(adjustWidth || adjustHeight)) {
- return;
- }
-
- if (adjustWidth) {
- if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
- bounds.left = bounds.right - minWidth;
- } else {
- // Either left bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping left.
- bounds.right = bounds.left + minWidth;
- }
- }
- if (adjustHeight) {
- if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
- bounds.top = bounds.bottom - minHeight;
- } else {
- // Either top bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping top.
- bounds.bottom = bounds.top + minHeight;
- }
- }
- }
-
- void setLastNonFullscreenBounds(Rect bounds) {
- if (mLastNonFullscreenBounds == null) {
- mLastNonFullscreenBounds = new Rect(bounds);
- } else {
- mLastNonFullscreenBounds.set(bounds);
- }
- }
-
- /**
- * This should be called when an child activity changes state. This should only
- * be called from
- * {@link ActivityRecord#setState(ActivityState, String)} .
- * @param record The {@link ActivityRecord} whose state has changed.
- * @param state The new state.
- * @param reason The reason for the change.
- */
- void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
- final ActivityStack parent = getStack();
-
- if (parent != null) {
- parent.onActivityStateChanged(record, state, reason);
- }
- }
-
- @Override
- public void onConfigurationChanged(Configuration newParentConfig) {
- // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
- // restore the last recorded non-fullscreen bounds.
- final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
- final boolean nextPersistTaskBounds =
- getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
- || newParentConfig.windowConfiguration.persistTaskBounds();
- if (!prevPersistTaskBounds && nextPersistTaskBounds
- && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
- // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
- getRequestedOverrideConfiguration().windowConfiguration
- .setBounds(mLastNonFullscreenBounds);
- }
-
- final boolean wasInMultiWindowMode = inMultiWindowMode();
- super.onConfigurationChanged(newParentConfig);
- if (wasInMultiWindowMode != inMultiWindowMode()) {
- mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
- }
-
- // If the configuration supports persistent bounds (eg. Freeform), keep track of the
- // current (non-fullscreen) bounds for persistence.
- if (getWindowConfiguration().persistTaskBounds()) {
- final Rect currentBounds = getRequestedOverrideBounds();
- if (!currentBounds.isEmpty()) {
- setLastNonFullscreenBounds(currentBounds);
- }
- }
- // TODO: Should also take care of Pip mode changes here.
-
- saveLaunchingStateIfNeeded();
- }
-
- /**
- * Saves launching state if necessary so that we can launch the activity to its latest state.
- * It only saves state if this task has been shown to user and it's in fullscreen or freeform
- * mode on freeform displays.
- */
- void saveLaunchingStateIfNeeded() {
- if (!hasBeenVisible) {
- // Not ever visible to user.
- return;
- }
-
- final int windowingMode = getWindowingMode();
- if (windowingMode != WINDOWING_MODE_FULLSCREEN
- && windowingMode != WINDOWING_MODE_FREEFORM) {
- return;
- }
-
- // Don't persist state if display isn't in freeform mode. Then the task will be launched
- // back to its last state in a freeform display when it's launched in a freeform display
- // next time.
- if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
- return;
- }
-
- // Saves the new state so that we can launch the activity at the same location.
- mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
- }
-
- /**
- * Adjust bounds to stay within stack bounds.
- *
- * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
- * that keep them unchanged, but be contained within the stack bounds.
- *
- * @param bounds Bounds to be adjusted.
- * @param stackBounds Bounds within which the other bounds should remain.
- * @param overlapPxX The amount of px required to be visible in the X dimension.
- * @param overlapPxY The amount of px required to be visible in the Y dimension.
- */
- private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
- int overlapPxY) {
- if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
- return;
- }
-
- // For each side of the parent (eg. left), check if the opposing side of the window (eg.
- // right) is at least overlap pixels away. If less, offset the window by that difference.
- int horizontalDiff = 0;
- // If window is smaller than overlap, use it's smallest dimension instead
- int overlapLR = Math.min(overlapPxX, bounds.width());
- if (bounds.right < (stackBounds.left + overlapLR)) {
- horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
- } else if (bounds.left > (stackBounds.right - overlapLR)) {
- horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
- }
- int verticalDiff = 0;
- int overlapTB = Math.min(overlapPxY, bounds.width());
- if (bounds.bottom < (stackBounds.top + overlapTB)) {
- verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
- } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
- verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
- }
- bounds.offset(horizontalDiff, verticalDiff);
- }
-
- /**
- * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
- * intersectBounds on a side, then the respective side will not be intersected.
- *
- * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
- * inset on that side is no-longer applicable. This scenario happens when a task's minimal
- * bounds are larger than the provided parent/display bounds.
- *
- * @param inOutBounds the bounds to intersect.
- * @param intersectBounds the bounds to intersect with.
- * @param intersectInsets insets to apply to intersectBounds before intersecting.
- */
- static void intersectWithInsetsIfFits(
- Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
- if (inOutBounds.right <= intersectBounds.right) {
- inOutBounds.right =
- Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
- }
- if (inOutBounds.bottom <= intersectBounds.bottom) {
- inOutBounds.bottom =
- Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
- }
- if (inOutBounds.left >= intersectBounds.left) {
- inOutBounds.left =
- Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
- }
- if (inOutBounds.top >= intersectBounds.top) {
- inOutBounds.top =
- Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
- }
- }
-
- /**
- * Gets bounds with non-decor and stable insets applied respectively.
- *
- * If bounds overhangs the display, those edges will not get insets. See
- * {@link #intersectWithInsetsIfFits}
- *
- * @param outNonDecorBounds where to place bounds with non-decor insets applied.
- * @param outStableBounds where to place bounds with stable insets applied.
- * @param bounds the bounds to inset.
- */
- private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
- DisplayInfo displayInfo) {
- outNonDecorBounds.set(bounds);
- outStableBounds.set(bounds);
- if (getStack() == null || getStack().getDisplay() == null) {
- return;
- }
- DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
- if (policy == null) {
- return;
- }
- mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-
- policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
- displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
- intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
-
- policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
- intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
- }
-
- /**
- * Asks docked-divider controller for the smallestwidthdp given bounds.
- * @param bounds bounds to calculate smallestwidthdp for.
- */
- private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
- DisplayContent dc = mStack.getDisplay().mDisplayContent;
- if (dc != null) {
- return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
- }
- return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
- }
-
- void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig) {
- computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
- }
-
- /**
- * Calculates configuration values used by the client to get resources. This should be run
- * using app-facing bounds (bounds unmodified by animations or transient interactions).
- *
- * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
- * configuring an "inherit-bounds" window which means that all configuration settings would
- * just be inherited from the parent configuration.
- **/
- void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig,
- @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
- int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- windowingMode = parentConfig.windowConfiguration.getWindowingMode();
- }
-
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = parentConfig.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
-
- final Rect bounds = inOutConfig.windowConfiguration.getBounds();
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(bounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- }
- // Non-null compatibility insets means the activity prefers to keep its original size, so
- // the out bounds doesn't need to be restricted by the parent.
- final boolean insideParentBounds = compatInsets == null;
- if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
- final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
- if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
- outAppBounds.intersect(parentAppBounds);
- }
- }
-
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
- || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- if (insideParentBounds && mStack != null) {
- final DisplayInfo di = new DisplayInfo();
- mStack.getDisplay().mDisplay.getDisplayInfo(di);
-
- // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
- // area, i.e. the screen area without the system bars.
- // The non decor inset are areas that could never be removed in Honeycomb. See
- // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
- calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
- } else {
- // Apply the given non-decor and stable insets to calculate the corresponding bounds
- // for screen size of configuration.
- int rotation = inOutConfig.windowConfiguration.getRotation();
- if (rotation == ROTATION_UNDEFINED) {
- rotation = parentConfig.windowConfiguration.getRotation();
- }
- if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
- mTmpNonDecorBounds.set(bounds);
- mTmpStableBounds.set(bounds);
- compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
- intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
- compatInsets.mNonDecorInsets[rotation]);
- intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
- compatInsets.mStableInsets[rotation]);
- outAppBounds.set(mTmpNonDecorBounds);
- } else {
- // Set to app bounds because it excludes decor insets.
- mTmpNonDecorBounds.set(outAppBounds);
- mTmpStableBounds.set(outAppBounds);
- }
- }
-
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
- inOutConfig.screenWidthDp = insideParentBounds
- ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
- : overrideScreenWidthDp;
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
- inOutConfig.screenHeightDp = insideParentBounds
- ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
- : overrideScreenHeightDp;
- }
-
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
- if (WindowConfiguration.isFloating(windowingMode)) {
- // For floating tasks, calculate the smallest width from the bounds of the task
- inOutConfig.smallestScreenWidthDp = (int) (
- Math.min(bounds.width(), bounds.height()) / density);
- } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
- // Iterating across all screen orientations, and return the minimum of the task
- // width taking into account that the bounds might change because the snap
- // algorithm snaps to a different value
- inOutConfig.smallestScreenWidthDp =
- getSmallestScreenWidthDpForDockedBounds(bounds);
- }
- // otherwise, it will just inherit
- }
- }
-
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
- if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
- // For calculating screen layout, we need to use the non-decor inset screen area for the
- // calculation for compatibility reasons, i.e. screen area without system bars that
- // could never go away in Honeycomb.
- final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
- final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
- // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
- // override calculation with partial default.
- // Reducing the screen layout starting from its parent config.
- final int sl = parentConfig.screenLayout
- & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
- final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
- final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
- inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
- }
- }
-
- @Override
- void resolveOverrideConfiguration(Configuration newParentConfig) {
- mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
- super.resolveOverrideConfiguration(newParentConfig);
- int windowingMode =
- getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
- }
- Rect outOverrideBounds =
- getResolvedOverrideConfiguration().windowConfiguration.getBounds();
-
- if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
- newParentConfig.windowConfiguration.getBounds(),
- newParentConfig.orientation);
- }
-
- if (outOverrideBounds.isEmpty()) {
- // If the task fills the parent, just inherit all the other configs from parent.
- return;
- }
-
- adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
- if (windowingMode == WINDOWING_MODE_FREEFORM) {
- // by policy, make sure the window remains within parent somewhere
- final float density =
- ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
- final Rect parentBounds =
- new Rect(newParentConfig.windowConfiguration.getBounds());
- final ActivityDisplay display = mStack.getDisplay();
- if (display != null && display.mDisplayContent != null) {
- // If a freeform window moves below system bar, there is no way to move it again
- // by touch. Because its caption is covered by system bar. So we exclude them
- // from stack bounds. and then caption will be shown inside stable area.
- final Rect stableBounds = new Rect();
- display.mDisplayContent.getStableRect(stableBounds);
- parentBounds.intersect(stableBounds);
- }
-
- fitWithinBounds(outOverrideBounds, parentBounds,
- (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
- (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
-
- // Prevent to overlap caption with stable insets.
- final int offsetTop = parentBounds.top - outOverrideBounds.top;
- if (offsetTop > 0) {
- outOverrideBounds.offset(0, offsetTop);
- }
- }
- computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
- }
-
- /**
- * Compute bounds (letterbox or pillarbox) for
- * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
- * orientation change and the requested orientation is different from the parent.
- */
- void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
- @NonNull Rect parentBounds, int parentOrientation) {
- // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
- outBounds.setEmpty();
- if (handlesOrientationChangeFromDescendant()) {
- return;
- }
- if (refActivity == null) {
- // Use the top activity as the reference of orientation. Don't include overlays because
- // it is usually not the actual content or just temporarily shown.
- // E.g. ForcedResizableInfoActivity.
- refActivity = getTopActivity(false /* includeOverlays */);
- }
-
- // If the task or the reference activity requires a different orientation (either by
- // override or activityInfo), make it fit the available bounds by scaling down its bounds.
- final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
- final int forcedOrientation =
- (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
- ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
- if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
- return;
- }
-
- final int parentWidth = parentBounds.width();
- final int parentHeight = parentBounds.height();
- final float aspect = ((float) parentHeight) / parentWidth;
- if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int height = (int) (parentWidth / aspect);
- final int top = parentBounds.centerY() - height / 2;
- outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
- } else {
- final int width = (int) (parentHeight * aspect);
- final int left = parentBounds.centerX() - width / 2;
- outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
- }
- }
-
- Rect updateOverrideConfigurationFromLaunchBounds() {
- final Rect bounds = getLaunchBounds();
- setBounds(bounds);
- if (bounds != null && !bounds.isEmpty()) {
- // TODO: Review if we actually want to do this - we are setting the launch bounds
- // directly here.
- bounds.set(getRequestedOverrideBounds());
- }
- return bounds;
- }
-
- /** Updates the task's bounds and override configuration to match what is expected for the
- * input stack. */
- void updateOverrideConfigurationForStack(ActivityStack inStack) {
- if (mStack != null && mStack == inStack) {
- return;
- }
-
- if (inStack.inFreeformWindowingMode()) {
- if (!isResizeable()) {
- throw new IllegalArgumentException("Can not position non-resizeable task="
- + this + " in stack=" + inStack);
- }
- if (!matchParentBounds()) {
- return;
- }
- if (mLastNonFullscreenBounds != null) {
- setBounds(mLastNonFullscreenBounds);
- } else {
- mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
- }
- } else {
- setBounds(inStack.getRequestedOverrideBounds());
- }
- }
-
- /** Returns the bounds that should be used to launch this task. */
- Rect getLaunchBounds() {
- if (mStack == null) {
- return null;
- }
-
- final int windowingMode = getWindowingMode();
- if (!isActivityTypeStandardOrUndefined()
- || windowingMode == WINDOWING_MODE_FULLSCREEN
- || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
- return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
- } else if (!getWindowConfiguration().persistTaskBounds()) {
- return mStack.getRequestedOverrideBounds();
- }
- return mLastNonFullscreenBounds;
- }
-
- void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.visible) {
- r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
- }
- }
- }
-
- void setRootProcess(WindowProcessController proc) {
- clearRootProcess();
- if (intent != null &&
- (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
- mRootProcess = proc;
- mRootProcess.addRecentTask(this);
- }
- }
-
- void clearRootProcess() {
- if (mRootProcess != null) {
- mRootProcess.removeRecentTask(this);
- mRootProcess = null;
- }
- }
-
- void clearAllPendingOptions() {
- for (int i = getChildCount() - 1; i >= 0; i--) {
- getChildAt(i).clearOptionsLocked(false /* withAbort */);
- }
- }
-
- /**
- * Fills in a {@link TaskInfo} with information from this task.
- * @param info the {@link TaskInfo} to fill in
- */
- void fillTaskInfo(TaskInfo info) {
- getNumRunningActivities(mReuseActivitiesReport);
- info.userId = mUserId;
- info.stackId = getStackId();
- info.taskId = mTaskId;
- info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
- info.isRunning = getTopActivity() != null;
- info.baseIntent = new Intent(getBaseIntent());
- info.baseActivity = mReuseActivitiesReport.base != null
- ? mReuseActivitiesReport.base.intent.getComponent()
- : null;
- info.topActivity = mReuseActivitiesReport.top != null
- ? mReuseActivitiesReport.top.mActivityComponent
- : null;
- info.origActivity = origActivity;
- info.realActivity = realActivity;
- info.numActivities = mReuseActivitiesReport.numActivities;
- info.lastActiveTime = lastActiveTime;
- info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
- info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
- info.resizeMode = mResizeMode;
- info.configuration.setTo(getConfiguration());
- }
-
- /**
- * Returns a {@link TaskInfo} with information from this task.
- */
- ActivityManager.RunningTaskInfo getTaskInfo() {
- ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
- fillTaskInfo(info);
- return info;
- }
-
- void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("userId="); pw.print(mUserId);
- pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
- pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
- pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
- pw.print(" mCallingPackage="); pw.println(mCallingPackage);
- if (affinity != null || rootAffinity != null) {
- pw.print(prefix); pw.print("affinity="); pw.print(affinity);
- if (affinity == null || !affinity.equals(rootAffinity)) {
- pw.print(" root="); pw.println(rootAffinity);
- } else {
- pw.println();
- }
- }
- if (voiceSession != null || voiceInteractor != null) {
- pw.print(prefix); pw.print("VOICE: session=0x");
- pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
- pw.print(" interactor=0x");
- pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
- }
- if (intent != null) {
- StringBuilder sb = new StringBuilder(128);
- sb.append(prefix); sb.append("intent={");
- intent.toShortString(sb, false, true, false, false);
- sb.append('}');
- pw.println(sb.toString());
- }
- if (affinityIntent != null) {
- StringBuilder sb = new StringBuilder(128);
- sb.append(prefix); sb.append("affinityIntent={");
- affinityIntent.toShortString(sb, false, true, false, false);
- sb.append('}');
- pw.println(sb.toString());
- }
- if (origActivity != null) {
- pw.print(prefix); pw.print("origActivity=");
- pw.println(origActivity.flattenToShortString());
- }
- if (realActivity != null) {
- pw.print(prefix); pw.print("mActivityComponent=");
- pw.println(realActivity.flattenToShortString());
- }
- if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) {
- pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
- pw.print(" isPersistable="); pw.print(isPersistable);
- pw.print(" numFullscreen="); pw.print(numFullscreen);
- pw.print(" activityType="); pw.println(getActivityType());
- }
- if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
- || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
- pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
- pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
- pw.print(" mReuseTask="); pw.print(mReuseTask);
- pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
- }
- if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
- || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
- || mNextAffiliate != null) {
- pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
- pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
- pw.print(" (");
- if (mPrevAffiliate == null) {
- pw.print("null");
- } else {
- pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
- }
- pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
- pw.print(" (");
- if (mNextAffiliate == null) {
- pw.print("null");
- } else {
- pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
- }
- pw.println(")");
- }
- pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
- if (!askedCompatMode || !inRecents || !isAvailable) {
- pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
- pw.print(" inRecents="); pw.print(inRecents);
- pw.print(" isAvailable="); pw.println(isAvailable);
- }
- if (lastDescription != null) {
- pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
- }
- if (mRootProcess != null) {
- pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
- }
- pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
- pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
- pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
- pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
- pw.print(" isResizeable=" + isResizeable());
- pw.print(" lastActiveTime=" + lastActiveTime);
- pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(128);
- if (stringName != null) {
- sb.append(stringName);
- sb.append(" U=");
- sb.append(mUserId);
- sb.append(" StackId=");
- sb.append(getStackId());
- sb.append(" sz=");
- sb.append(getChildCount());
- sb.append('}');
- return sb.toString();
- }
- sb.append("TaskRecord{");
- sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(" #");
- sb.append(mTaskId);
- if (affinity != null) {
- sb.append(" A=");
- sb.append(affinity);
- } else if (intent != null) {
- sb.append(" I=");
- sb.append(intent.getComponent().flattenToShortString());
- } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
- sb.append(" aI=");
- sb.append(affinityIntent.getComponent().flattenToShortString());
- } else {
- sb.append(" ??");
- }
- stringName = sb.toString();
- return toString();
- }
-
- @Override
- public void writeToProto(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- writeToProtoInnerTaskOnly(proto, TASK, logLevel);
- proto.write(ID, mTaskId);
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord activity = getChildAt(i);
- activity.writeToProto(proto, ACTIVITIES);
- }
- proto.write(STACK_ID, getStackId());
- if (mLastNonFullscreenBounds != null) {
- mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
- }
- if (realActivity != null) {
- proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
- }
- if (origActivity != null) {
- proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
- }
- proto.write(ACTIVITY_TYPE, getActivityType());
- proto.write(RESIZE_MODE, mResizeMode);
- // TODO: Remove, no longer needed with windowingMode.
- proto.write(FULLSCREEN, matchParentBounds());
-
- if (!matchParentBounds()) {
- final Rect bounds = getRequestedOverrideBounds();
- bounds.writeToProto(proto, BOUNDS);
- }
- proto.write(MIN_WIDTH, mMinWidth);
- proto.write(MIN_HEIGHT, mMinHeight);
- proto.end(token);
- }
-
- /**
- * See {@link #getNumRunningActivities(TaskActivitiesReport)}.
- */
- static class TaskActivitiesReport {
- int numRunning;
- int numActivities;
- ActivityRecord top;
- ActivityRecord base;
-
- void reset() {
- numRunning = numActivities = 0;
- top = base = null;
- }
- }
-
- /**
- * Saves this {@link TaskRecord} to XML using given serializer.
- */
- void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
- if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
-
- out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
- if (realActivity != null) {
- out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
- }
- out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
- if (origActivity != null) {
- out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
- }
- // Write affinity, and root affinity if it is different from affinity.
- // We use the special string "@" for a null root affinity, so we can identify
- // later whether we were given a root affinity or should just make it the
- // same as the affinity.
- if (affinity != null) {
- out.attribute(null, ATTR_AFFINITY, affinity);
- if (!affinity.equals(rootAffinity)) {
- out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
- }
- } else if (rootAffinity != null) {
- out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
- }
- out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
- out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
- out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
- out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
- out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
- out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
- out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
- out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
- if (lastDescription != null) {
- out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
- }
- if (getTaskDescription() != null) {
- getTaskDescription().saveToXml(out);
- }
- out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
- out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
- out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
- out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
- out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
- out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
- out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
- out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
- String.valueOf(mSupportsPictureInPicture));
- if (mLastNonFullscreenBounds != null) {
- out.attribute(
- null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
- }
- out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
- out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
- out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
-
- if (affinityIntent != null) {
- out.startTag(null, TAG_AFFINITYINTENT);
- affinityIntent.saveToXml(out);
- out.endTag(null, TAG_AFFINITYINTENT);
- }
-
- if (intent != null) {
- out.startTag(null, TAG_INTENT);
- intent.saveToXml(out);
- out.endTag(null, TAG_INTENT);
- }
-
- final int numActivities = getChildCount();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
- ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
- | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
- activityNdx > 0) {
- // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
- break;
- }
- out.startTag(null, TAG_ACTIVITY);
- r.saveToXml(out);
- out.endTag(null, TAG_ACTIVITY);
- }
- }
-
- @VisibleForTesting
- static TaskRecordFactory getTaskRecordFactory() {
- if (sTaskRecordFactory == null) {
- setTaskRecordFactory(new TaskRecordFactory());
- }
- return sTaskRecordFactory;
- }
-
- static void setTaskRecordFactory(TaskRecordFactory factory) {
- sTaskRecordFactory = factory;
- }
-
- static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor, ActivityStack stack) {
- return getTaskRecordFactory().create(
- service, taskId, info, intent, voiceSession, voiceInteractor, stack);
- }
-
- static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, TaskDescription taskDescription, ActivityStack stack) {
- return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack);
- }
-
- static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
- throws IOException, XmlPullParserException {
- return getTaskRecordFactory().restoreFromXml(in, stackSupervisor);
- }
-
- /**
- * A factory class used to create {@link TaskRecord} or its subclass if any. This can be
- * specified when system boots by setting it with
- * {@link #setTaskRecordFactory(TaskRecordFactory)}.
- */
- static class TaskRecordFactory {
-
- TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, IVoiceInteractionSession voiceSession,
- IVoiceInteractor voiceInteractor, ActivityStack stack) {
- return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor,
- null /*taskDescription*/, stack);
- }
-
- TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
- Intent intent, TaskDescription taskDescription, ActivityStack stack) {
- return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/,
- null /*voiceInteractor*/, taskDescription, stack);
- }
-
- /**
- * Should only be used when we're restoring {@link TaskRecord} from storage.
- */
- TaskRecord create(ActivityTaskManagerService service, int taskId, Intent intent,
- Intent affinityIntent, String affinity, String rootAffinity,
- ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
- boolean autoRemoveRecents, boolean askedCompatMode, int userId,
- int effectiveUid, String lastDescription,
- long lastTimeMoved, boolean neverRelinquishIdentity,
- TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
- int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
- boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
- return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
- rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
- askedCompatMode, userId, effectiveUid, lastDescription,
- lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
- prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
- resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
- minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
- null /*_voiceInteractor*/, stack);
- }
-
- TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
- throws IOException, XmlPullParserException {
- Intent intent = null;
- Intent affinityIntent = null;
- ArrayList<ActivityRecord> activities = new ArrayList<>();
- ComponentName realActivity = null;
- boolean realActivitySuspended = false;
- ComponentName origActivity = null;
- String affinity = null;
- String rootAffinity = null;
- boolean hasRootAffinity = false;
- boolean rootHasReset = false;
- boolean autoRemoveRecents = false;
- boolean askedCompatMode = false;
- int taskType = 0;
- int userId = 0;
- boolean userSetupComplete = true;
- int effectiveUid = -1;
- String lastDescription = null;
- long lastTimeOnTop = 0;
- boolean neverRelinquishIdentity = true;
- int taskId = INVALID_TASK_ID;
- final int outerDepth = in.getDepth();
- TaskDescription taskDescription = new TaskDescription();
- int taskAffiliation = INVALID_TASK_ID;
- int taskAffiliationColor = 0;
- int prevTaskId = INVALID_TASK_ID;
- int nextTaskId = INVALID_TASK_ID;
- int callingUid = -1;
- String callingPackage = "";
- int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
- boolean supportsPictureInPicture = false;
- Rect lastNonFullscreenBounds = null;
- int minWidth = INVALID_MIN_SIZE;
- int minHeight = INVALID_MIN_SIZE;
- int persistTaskVersion = 0;
-
- for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
- final String attrName = in.getAttributeName(attrNdx);
- final String attrValue = in.getAttributeValue(attrNdx);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
- attrName + " value=" + attrValue);
- switch (attrName) {
- case ATTR_TASKID:
- if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
- break;
- case ATTR_REALACTIVITY:
- realActivity = ComponentName.unflattenFromString(attrValue);
- break;
- case ATTR_REALACTIVITY_SUSPENDED:
- realActivitySuspended = Boolean.valueOf(attrValue);
- break;
- case ATTR_ORIGACTIVITY:
- origActivity = ComponentName.unflattenFromString(attrValue);
- break;
- case ATTR_AFFINITY:
- affinity = attrValue;
- break;
- case ATTR_ROOT_AFFINITY:
- rootAffinity = attrValue;
- hasRootAffinity = true;
- break;
- case ATTR_ROOTHASRESET:
- rootHasReset = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_AUTOREMOVERECENTS:
- autoRemoveRecents = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_ASKEDCOMPATMODE:
- askedCompatMode = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_USERID:
- userId = Integer.parseInt(attrValue);
- break;
- case ATTR_USER_SETUP_COMPLETE:
- userSetupComplete = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_EFFECTIVE_UID:
- effectiveUid = Integer.parseInt(attrValue);
- break;
- case ATTR_TASKTYPE:
- taskType = Integer.parseInt(attrValue);
- break;
- case ATTR_LASTDESCRIPTION:
- lastDescription = attrValue;
- break;
- case ATTR_LASTTIMEMOVED:
- lastTimeOnTop = Long.parseLong(attrValue);
- break;
- case ATTR_NEVERRELINQUISH:
- neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_TASK_AFFILIATION:
- taskAffiliation = Integer.parseInt(attrValue);
- break;
- case ATTR_PREV_AFFILIATION:
- prevTaskId = Integer.parseInt(attrValue);
- break;
- case ATTR_NEXT_AFFILIATION:
- nextTaskId = Integer.parseInt(attrValue);
- break;
- case ATTR_TASK_AFFILIATION_COLOR:
- taskAffiliationColor = Integer.parseInt(attrValue);
- break;
- case ATTR_CALLING_UID:
- callingUid = Integer.parseInt(attrValue);
- break;
- case ATTR_CALLING_PACKAGE:
- callingPackage = attrValue;
- break;
- case ATTR_RESIZE_MODE:
- resizeMode = Integer.parseInt(attrValue);
- break;
- case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
- supportsPictureInPicture = Boolean.parseBoolean(attrValue);
- break;
- case ATTR_NON_FULLSCREEN_BOUNDS:
- lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
- break;
- case ATTR_MIN_WIDTH:
- minWidth = Integer.parseInt(attrValue);
- break;
- case ATTR_MIN_HEIGHT:
- minHeight = Integer.parseInt(attrValue);
- break;
- case ATTR_PERSIST_TASK_VERSION:
- persistTaskVersion = Integer.parseInt(attrValue);
- break;
- default:
- if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
- taskDescription.restoreFromXml(attrName, attrValue);
- } else {
- Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
- }
- }
- }
-
- int event;
- while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
- if (event == XmlPullParser.START_TAG) {
- final String name = in.getName();
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
- "TaskRecord: START_TAG name=" + name);
- if (TAG_AFFINITYINTENT.equals(name)) {
- affinityIntent = Intent.restoreFromXml(in);
- } else if (TAG_INTENT.equals(name)) {
- intent = Intent.restoreFromXml(in);
- } else if (TAG_ACTIVITY.equals(name)) {
- ActivityRecord activity =
- ActivityRecord.restoreFromXml(in, stackSupervisor);
- if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
- activity);
- if (activity != null) {
- activities.add(activity);
- }
- } else {
- handleUnknownTag(name, in);
- }
- }
- }
- if (!hasRootAffinity) {
- rootAffinity = affinity;
- } else if ("@".equals(rootAffinity)) {
- rootAffinity = null;
- }
- if (effectiveUid <= 0) {
- Intent checkIntent = intent != null ? intent : affinityIntent;
- effectiveUid = 0;
- if (checkIntent != null) {
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- ApplicationInfo ai = pm.getApplicationInfo(
- checkIntent.getComponent().getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
- if (ai != null) {
- effectiveUid = ai.uid;
- }
- } catch (RemoteException e) {
- }
- }
- Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
- + ": effectiveUid=" + effectiveUid);
- }
-
- if (persistTaskVersion < 1) {
- // We need to convert the resize mode of home activities saved before version one if
- // they are marked as RESIZE_MODE_RESIZEABLE to
- // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
- // before version 1 and the system didn't resize home activities before then.
- if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
- resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
- }
- } else {
- // This activity has previously marked itself explicitly as both resizeable and
- // supporting picture-in-picture. Since there is no longer a requirement for
- // picture-in-picture activities to be resizeable, we can mark this simply as
- // resizeable and supporting picture-in-picture separately.
- if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
- resizeMode = RESIZE_MODE_RESIZEABLE;
- supportsPictureInPicture = true;
- }
- }
-
- final TaskRecord task = create(stackSupervisor.mService,
- taskId, intent, affinityIntent,
- affinity, rootAffinity, realActivity, origActivity, rootHasReset,
- autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
- lastTimeOnTop, neverRelinquishIdentity, taskDescription,
- taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
- callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
- userSetupComplete, minWidth, minHeight, null /*stack*/);
- task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
- task.setBounds(lastNonFullscreenBounds);
-
- for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
- task.addChild(activities.get(activityNdx));
- }
-
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
- return task;
- }
-
- void handleUnknownTag(String name, XmlPullParser in)
- throws IOException, XmlPullParserException {
- Slog.e(TAG, "restoreTask: Unexpected name=" + name);
- XmlUtils.skipCurrentTag(in);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 0d4ec652f3bb..35f61a88522b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -248,6 +250,12 @@ class TaskSnapshotController {
@Nullable
SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction) {
+ return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888);
+ }
+
+ @Nullable
+ SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
+ float scaleFraction, int pixelFormat) {
if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) {
Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -258,7 +266,7 @@ class TaskSnapshotController {
mTmpRect.offsetTo(0, 0);
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
SurfaceControl.captureLayers(
- task.getSurfaceControl(), mTmpRect, scaleFraction);
+ task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat);
final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
: null;
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -299,8 +307,14 @@ class TaskSnapshotController {
Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
return null;
}
+ final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
+ final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
+ final int pixelFormat = mPersister.use16BitFormat() && activity.fillsParent()
+ && !(isWindowTranslucent && isShowWallpaper)
+ ? PixelFormat.RGB_565
+ : PixelFormat.RGBA_8888;
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
- createTaskSnapshot(task, scaleFraction);
+ createTaskSnapshot(task, scaleFraction, pixelFormat);
if (screenshotBuffer == null) {
if (DEBUG_SCREENSHOT) {
@@ -308,7 +322,8 @@ class TaskSnapshotController {
}
return null;
}
- final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
+ final boolean isTranslucent = PixelFormat.formatHasAlpha(pixelFormat)
+ && (!activity.fillsParent() || isWindowTranslucent);
return new TaskSnapshot(
System.currentTimeMillis() /* id */,
activity.mActivityComponent, screenshotBuffer.getGraphicBuffer(),
@@ -316,7 +331,7 @@ class TaskSnapshotController {
activity.getTask().getConfiguration().orientation,
getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */,
true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
- !activity.fillsParent() || isWindowTranslucent);
+ isTranslucent);
}
private boolean shouldDisableSnapshots() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 696e1c3a2602..22c1ea59d176 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -75,25 +75,35 @@ class TaskSnapshotLoader {
final byte[] bytes = Files.readAllBytes(protoFile.toPath());
final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
final Options options = new Options();
- options.inPreferredConfig = Config.HARDWARE;
+ options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent
+ ? Config.RGB_565
+ : Config.ARGB_8888;
final Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath(), options);
if (bitmap == null) {
Slog.w(TAG, "Failed to load bitmap: " + bitmapFile.getPath());
return null;
}
- final GraphicBuffer buffer = bitmap.createGraphicBufferHandle();
+
+ final Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
+ bitmap.recycle();
+ if (hwBitmap == null) {
+ Slog.w(TAG, "Failed to create hardware bitmap: " + bitmapFile.getPath());
+ return null;
+ }
+ final GraphicBuffer buffer = hwBitmap.createGraphicBufferHandle();
if (buffer == null) {
Slog.w(TAG, "Failed to retrieve gralloc buffer for bitmap: "
+ bitmapFile.getPath());
return null;
}
+
final ComponentName topActivityComponent = ComponentName.unflattenFromString(
proto.topActivityComponent);
// For legacy snapshots, restore the scale based on the reduced resolution state
final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f;
final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale;
- return new TaskSnapshot(proto.id, topActivityComponent, buffer, bitmap.getColorSpace(),
- proto.orientation,
+ return new TaskSnapshot(proto.id, topActivityComponent, buffer,
+ hwBitmap.getColorSpace(), proto.orientation,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode,
proto.systemUiVisibility, proto.isTranslucent);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index a156f5c240a8..59155907823b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -74,6 +74,7 @@ class TaskSnapshotPersister {
private final Object mLock = new Object();
private final DirectoryResolver mDirectoryResolver;
private final float mReducedScale;
+ private final boolean mUse16BitFormat;
/**
* The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
@@ -92,6 +93,8 @@ class TaskSnapshotPersister {
mReducedScale = ActivityManager.isLowRamDeviceStatic()
? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
}
+ mUse16BitFormat = service.mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
}
/**
@@ -164,6 +167,15 @@ class TaskSnapshotPersister {
return mReducedScale;
}
+ /**
+ * Return if task snapshots are stored in 16 bit pixel format.
+ *
+ * @return true if task snapshots are stored in 16 bit pixel format.
+ */
+ boolean use16BitFormat() {
+ return mUse16BitFormat;
+ }
+
@TestApi
void waitForQueueEmpty() {
while (true) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index b1e5c8f7f5ee..b3750e95fb36 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -209,7 +209,7 @@ class TaskSnapshotSurface implements StartingSurface {
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
- tmpRect, tmpCutout, null, mTmpInsetsState);
+ tmpCutout, null, mTmpInsetsState);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
@@ -224,7 +224,7 @@ class TaskSnapshotSurface implements StartingSurface {
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
- tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
+ tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
} catch (RemoteException e) {
// Local call.
@@ -466,8 +466,8 @@ class TaskSnapshotSurface implements StartingSurface {
}
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw,
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+ Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 870ecccf66dc..ec627c881709 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -58,7 +58,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.CallSuper;
import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Point;
@@ -84,7 +83,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-public class TaskStack extends WindowContainer<TaskRecord> implements
+public class TaskStack extends WindowContainer<Task> implements
BoundsAnimationTarget, ConfigurationContainerListener {
/** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
* restrict IME adjustment so that a min portion of top stack remains visible.*/
@@ -483,7 +482,7 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
* @param position Target position to add the task to.
* @param showForAllUsers Whether to show the task regardless of the current user.
*/
- void addChild(TaskRecord task, int position, boolean showForAllUsers, boolean moveParents) {
+ void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
// Add child task.
addChild(task, null);
@@ -496,11 +495,11 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
}
@Override
- void addChild(TaskRecord task, int position) {
+ void addChild(Task task, int position) {
addChild(task, position, task.showForAllUsers(), false /* includingParents */);
}
- void positionChildAt(TaskRecord child, int position) {
+ void positionChildAt(Task child, int position) {
if (DEBUG_STACK) {
Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
}
@@ -515,7 +514,7 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
- void positionChildAtTop(TaskRecord child, boolean includingParents) {
+ void positionChildAtTop(Task child, boolean includingParents) {
if (child == null) {
// TODO: Fix the call-points that cause this to happen.
return;
@@ -531,7 +530,7 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
displayContent.layoutAndAssignWindowLayersIfNeeded();
}
- void positionChildAtBottom(TaskRecord child, boolean includingParents) {
+ void positionChildAtBottom(Task child, boolean includingParents) {
if (child == null) {
// TODO: Fix the call-points that cause this to happen.
return;
@@ -546,7 +545,7 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
}
@Override
- void positionChildAt(int position, TaskRecord child, boolean includingParents) {
+ void positionChildAt(int position, Task child, boolean includingParents) {
positionChildAt(position, child, includingParents, child.showForAllUsers());
}
@@ -555,7 +554,7 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
* {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive
* showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}.
*/
- private int positionChildAt(int position, TaskRecord child, boolean includingParents,
+ private int positionChildAt(int position, Task child, boolean includingParents,
boolean showForAllUsers) {
final int targetPosition = findPositionForTask(child, position, showForAllUsers);
super.positionChildAt(targetPosition, child, includingParents);
@@ -572,8 +571,9 @@ public class TaskStack extends WindowContainer<TaskRecord> implements
@Override
void onChildPositionChanged(WindowContainer child) {
- // TODO(task-merge): Read comment on updateTaskMovement method.
- //((TaskRecord) child).updateTaskMovement(true);
+ if (mChildren.contains(child)) {
+ ((Task) child).updateTaskMovement(getTopChild() == child);
+ }
}
void reparent(DisplayContent newParent, boolean onTop) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 3632284fdeb6..6ff4b2e504f1 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -120,7 +120,7 @@ class WallpaperController {
}
mFindResults.resetTopWallpaper = true;
- if (w.mActivityRecord != null && w.mActivityRecord.isHidden()
+ if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
&& !w.mActivityRecord.isAnimating(TRANSITION)) {
// If this window's app token is hidden and not animating, it is of no interest to us.
@@ -278,9 +278,11 @@ class WallpaperController {
for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
final WallpaperWindowToken token = mWallpaperTokens.get(i);
token.hideWallpaperToken(wasDeferred, "hideWallpapers");
- if (DEBUG_WALLPAPER_LIGHT && !token.isHidden()) Slog.d(TAG, "Hiding wallpaper " + token
- + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
- + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) {
+ Slog.d(TAG, "Hiding wallpaper " + token
+ + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
+ + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " "));
+ }
}
}
@@ -532,9 +534,9 @@ class WallpaperController {
}
final boolean newTargetHidden = wallpaperTarget.mActivityRecord != null
- && wallpaperTarget.mActivityRecord.hiddenRequested;
+ && !wallpaperTarget.mActivityRecord.mVisibleRequested;
final boolean oldTargetHidden = prevWallpaperTarget.mActivityRecord != null
- && prevWallpaperTarget.mActivityRecord.hiddenRequested;
+ && !prevWallpaperTarget.mActivityRecord.mVisibleRequested;
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
+ prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 528cece9a78b..d23bf978cbab 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -56,7 +56,6 @@ class WallpaperWindowToken extends WindowToken {
final WindowState wallpaper = mChildren.get(j);
wallpaper.hideWallpaperWindow(wasDeferred, reason);
}
- setHidden(true);
}
void sendWindowWallpaperCommand(
@@ -88,9 +87,7 @@ class WallpaperWindowToken extends WindowToken {
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
- if (isHidden() == visible) {
- setHidden(!visible);
-
+ if (isVisible() != visible) {
// Need to do a layout to ensure the wallpaper now has the correct size.
mDisplayContent.setLayoutNeeded();
}
@@ -118,10 +115,9 @@ class WallpaperWindowToken extends WindowToken {
void updateWallpaperWindows(boolean visible) {
- if (isHidden() == visible) {
+ if (isVisible() != visible) {
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
- "Wallpaper token " + token + " hidden=" + !visible);
- setHidden(!visible);
+ "Wallpaper token " + token + " visible=" + visible);
// Need to do a layout to ensure the wallpaper now has the correct size.
mDisplayContent.setLayoutNeeded();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index cf3e2bbe1569..6fed2cbf03be 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -490,6 +490,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
mSurfaceControl = null;
+ mLastSurfacePosition.set(0, 0);
scheduleAnimation();
}
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9fe47604d704..70fc19470f83 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -23,10 +23,6 @@ import static com.android.server.wm.WindowFramesProto.CUTOUT;
import static com.android.server.wm.WindowFramesProto.DECOR_FRAME;
import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
import static com.android.server.wm.WindowFramesProto.FRAME;
-import static com.android.server.wm.WindowFramesProto.OUTSETS;
-import static com.android.server.wm.WindowFramesProto.OUTSET_FRAME;
-import static com.android.server.wm.WindowFramesProto.OVERSCAN_FRAME;
-import static com.android.server.wm.WindowFramesProto.OVERSCAN_INSETS;
import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
import static com.android.server.wm.WindowFramesProto.STABLE_INSETS;
import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
@@ -70,14 +66,6 @@ public class WindowFrames {
public final Rect mDisplayFrame = new Rect();
/**
- * The region of the display frame that the display type supports displaying content on. This
- * is mostly a special case for TV where some displays don’t have the entire display usable.
- * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to
- * allow window display contents to extend into the overscan region.
- */
- public final Rect mOverscanFrame = new Rect();
-
- /**
* Legacy stuff. Generally equal to the content frame expect when the IME for older apps
* displays hint text.
*/
@@ -102,12 +90,6 @@ public class WindowFrames {
public final Rect mStableFrame = new Rect();
/**
- * Frame that includes dead area outside of the surface but where we want to pretend that it's
- * possible to draw.
- */
- final public Rect mOutsetFrame = new Rect();
-
- /**
* Similar to {@link #mDisplayFrame}
*
* TODO: Why is this different than mDisplayFrame
@@ -148,14 +130,6 @@ public class WindowFrames {
private boolean mDisplayCutoutChanged;
/**
- * Insets that determine the area covered by the display overscan region. These are in the
- * application's coordinate space (without compatibility scale applied).
- */
- final Rect mOverscanInsets = new Rect();
- final Rect mLastOverscanInsets = new Rect();
- private boolean mOverscanInsetsChanged;
-
- /**
* Insets that determine the area covered by the stable system windows. These are in the
* application's coordinate space (without compatibility scale applied).
*/
@@ -164,14 +138,6 @@ public class WindowFrames {
private boolean mStableInsetsChanged;
/**
- * Outsets determine the area outside of the surface where we want to pretend that it's possible
- * to draw anyway.
- */
- final Rect mOutsets = new Rect();
- final Rect mLastOutsets = new Rect();
- private boolean mOutsetsChanged = false;
-
- /**
* Insets that determine the actually visible area. These are in the application's
* coordinate space (without compatibility scale applied).
*/
@@ -190,30 +156,25 @@ public class WindowFrames {
private final Rect mTmpRect = new Rect();
- private boolean mHasOutsets;
-
private boolean mContentChanged;
public WindowFrames() {
}
- public WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame,
- Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame) {
- setFrames(parentFrame, displayFrame, overscanFrame, contentFrame, visibleFrame, decorFrame,
- stableFrame, outsetFrame);
+ public WindowFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame,
+ Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
+ setFrames(parentFrame, displayFrame, contentFrame, visibleFrame, decorFrame,
+ stableFrame);
}
- public void setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
- Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
- Rect outsetFrame) {
+ public void setFrames(Rect parentFrame, Rect displayFrame,
+ Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
mParentFrame.set(parentFrame);
mDisplayFrame.set(displayFrame);
- mOverscanFrame.set(overscanFrame);
mContentFrame.set(contentFrame);
mVisibleFrame.set(visibleFrame);
mDecorFrame.set(decorFrame);
mStableFrame.set(stableFrame);
- mOutsetFrame.set(outsetFrame);
}
public void setParentFrameWasClippedByDisplayCutout(
@@ -237,17 +198,6 @@ public class WindowFrames {
}
/**
- * Calculates the outsets for this windowFrame. The outsets are calculated by the area between
- * the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then
- * {@link #mOutsets} is set to empty.
- */
- void calculateOutsets() {
- if (mHasOutsets) {
- InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
- }
- }
-
- /**
* Calculate the insets for the type
* {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
*
@@ -301,11 +251,9 @@ public class WindowFrames {
* @param scale The amount to scale the insets by.
*/
void scaleInsets(float scale) {
- mOverscanInsets.scale(scale);
mContentInsets.scale(scale);
mVisibleInsets.scale(scale);
mStableInsets.scale(scale);
- mOutsets.scale(scale);
}
void offsetFrames(int layoutXDiff, int layoutYDiff) {
@@ -321,15 +269,13 @@ public class WindowFrames {
* @return true if info about size has changed since last reported.
*/
boolean setReportResizeHints() {
- mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
- mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
mFrameSizeChanged |= didFrameSizeChange();
mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
- return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
- || mStableInsetsChanged || mOutsetsChanged || mFrameSizeChanged
+ return mContentInsetsChanged || mVisibleInsetsChanged
+ || mStableInsetsChanged || mFrameSizeChanged
|| mDisplayCutoutChanged;
}
@@ -338,11 +284,9 @@ public class WindowFrames {
* after the insets are reported to client.
*/
void resetInsetsChanged() {
- mOverscanInsetsChanged = false;
mContentInsetsChanged = false;
mVisibleInsetsChanged = false;
mStableInsetsChanged = false;
- mOutsetsChanged = false;
mFrameSizeChanged = false;
mDisplayCutoutChanged = false;
}
@@ -351,11 +295,9 @@ public class WindowFrames {
* Copy over inset values as the last insets that were sent to the client.
*/
void updateLastInsetValues() {
- mLastOverscanInsets.set(mOverscanInsets);
mLastContentInsets.set(mContentInsets);
mLastVisibleInsets.set(mVisibleInsets);
mLastStableInsets.set(mStableInsets);
- mLastOutsets.set(mOutsets);
mLastDisplayCutout = mDisplayCutout;
}
@@ -368,19 +310,6 @@ public class WindowFrames {
}
/**
- * Sets whether the frame has outsets.
- */
- public void setHasOutsets(boolean hasOutsets) {
- if (mHasOutsets == hasOutsets) {
- return;
- }
- mHasOutsets = hasOutsets;
- if (!hasOutsets) {
- mOutsets.setEmpty();
- }
- }
-
- /**
* Sets whether the content has changed. This means that either the size or parent frame has
* changed.
*/
@@ -400,18 +329,14 @@ public class WindowFrames {
mParentFrame.writeToProto(proto, PARENT_FRAME);
mContentFrame.writeToProto(proto, CONTENT_FRAME);
mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
- mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
mDecorFrame.writeToProto(proto, DECOR_FRAME);
- mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
mFrame.writeToProto(proto, FRAME);
mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
mContentInsets.writeToProto(proto, CONTENT_INSETS);
- mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
mStableInsets.writeToProto(proto, STABLE_INSETS);
- mOutsets.writeToProto(proto, OUTSETS);
proto.end(token);
}
@@ -420,33 +345,26 @@ public class WindowFrames {
pw.println(prefix + "Frames: containing="
+ mContainingFrame.toShortString(sTmpSB)
+ " parent=" + mParentFrame.toShortString(sTmpSB));
- pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB)
- + " overscan=" + mOverscanFrame.toShortString(sTmpSB));
+ pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB));
pw.println(prefix + " content=" + mContentFrame.toShortString(sTmpSB)
+ " visible=" + mVisibleFrame.toShortString(sTmpSB));
pw.println(prefix + " decor=" + mDecorFrame.toShortString(sTmpSB));
- pw.println(prefix + " outset=" + mOutsetFrame.toShortString(sTmpSB));
pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
+ " last=" + mLastFrame.toShortString(sTmpSB));
pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
+ " last=" + mLastDisplayCutout.getDisplayCutout());
- pw.print(prefix + "Cur insets: overscan=" + mOverscanInsets.toShortString(sTmpSB)
- + " content=" + mContentInsets.toShortString(sTmpSB)
+ pw.print(prefix + "Cur insets: content=" + mContentInsets.toShortString(sTmpSB)
+ " visible=" + mVisibleInsets.toShortString(sTmpSB)
- + " stable=" + mStableInsets.toShortString(sTmpSB)
- + " outsets=" + mOutsets.toShortString(sTmpSB));
- pw.println(prefix + "Lst insets: overscan=" + mLastOverscanInsets.toShortString(sTmpSB)
- + " content=" + mLastContentInsets.toShortString(sTmpSB)
+ + " stable=" + mStableInsets.toShortString(sTmpSB));
+ pw.println(prefix + "Lst insets: content=" + mLastContentInsets.toShortString(sTmpSB)
+ " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
- + " stable=" + mLastStableInsets.toShortString(sTmpSB)
- + " outset=" + mLastOutsets.toShortString(sTmpSB));
+ + " stable=" + mLastStableInsets.toShortString(sTmpSB));
}
String getInsetsInfo() {
return "ci=" + mContentInsets.toShortString()
+ " vi=" + mVisibleInsets.toShortString()
- + " si=" + mStableInsets.toShortString()
- + " of=" + mOutsets.toShortString();
+ + " si=" + mStableInsets.toShortString();
}
String getInsetsChangedInfo() {
@@ -456,8 +374,6 @@ public class WindowFrames {
+ " " + mVisibleInsets.toShortString()
+ " stableInsetsChanged=" + mStableInsetsChanged
+ " " + mStableInsets.toShortString()
- + " outsetsChanged=" + mOutsetsChanged
- + " " + mOutsets.toShortString()
+ " displayCutoutChanged=" + mDisplayCutoutChanged;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fc8705bbaae6..6e4f1ee29a64 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
@@ -211,6 +212,8 @@ import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowListener;
+import android.view.IDisplayWindowRotationController;
import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
@@ -260,6 +263,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.LatencyTracker;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AnimationThread;
@@ -433,8 +437,10 @@ public class WindowManagerService extends IWindowManager.Stub
public void onVrStateChanged(boolean enabled) {
synchronized (mGlobalLock) {
mVrModeEnabled = enabled;
- mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
- DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled));
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled);
+ mRoot.forAllDisplayPolicies(c);
+ c.recycle();
}
}
};
@@ -591,7 +597,6 @@ public class WindowManagerService extends IWindowManager.Stub
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
- CircularDisplayMask mCircularDisplayMask;
EmulatorDisplayOverlay mEmulatorDisplayOverlay;
final float[] mTmpFloats = new float[9];
@@ -658,6 +663,12 @@ public class WindowManagerService extends IWindowManager.Stub
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
new WallpaperVisibilityListeners();
+ IDisplayWindowRotationController mDisplayRotationController = null;
+ private final DeathRecipient mDisplayRotationControllerDeath =
+ () -> mDisplayRotationController = null;
+
+ final DisplayWindowListenerController mDisplayNotificationController;
+
boolean mDisplayFrozen = false;
long mDisplayFreezeTime = 0;
int mLastDisplayFreezeDuration = 0;
@@ -760,11 +771,6 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mDisplayInversionEnabledUri.equals(uri)) {
- updateCircularDisplayMaskIfNeeded();
- return;
- }
-
if (mPointerLocationUri.equals(uri)) {
updatePointerLocation();
return;
@@ -827,9 +833,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
mPointerLocationEnabled = enablePointerLocation;
synchronized (mGlobalLock) {
- mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+ final PooledConsumer c = PooledLambda.obtainConsumer(
DisplayPolicy::setPointerLocationEnabled, PooledLambda.__(),
- mPointerLocationEnabled));
+ mPointerLocationEnabled);
+ mRoot.forAllDisplayPolicies(c);
+ c.recycle();
}
}
@@ -1181,6 +1189,8 @@ public class WindowManagerService extends IWindowManager.Stub
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
+ mDisplayNotificationController = new DisplayWindowListenerController(this);
+
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -1332,7 +1342,7 @@ public class WindowManagerService extends IWindowManager.Stub
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
- Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
+ Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
int[] appOp = new int[1];
@@ -1684,7 +1694,7 @@ public class WindowManagerService extends IWindowManager.Stub
floatingStack = false;
}
if (displayPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack,
- outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
+ outFrame, outContentInsets, outStableInsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
}
outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win));
@@ -1692,7 +1702,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
- if (win.mActivityRecord == null || !win.mActivityRecord.isClientHidden()) {
+ if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
@@ -2087,8 +2097,8 @@ public class WindowManagerService extends IWindowManager.Stub
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
- long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
- Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
+ long frameNumber, Rect outFrame, Rect outContentInsets,
+ Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
int result = 0;
@@ -2225,7 +2235,7 @@ public class WindowManagerService extends IWindowManager.Stub
// associated appToken is not hidden.
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
- || !win.mActivityRecord.isClientHidden());
+ || win.mActivityRecord.isClientVisible());
// If we are not currently running the exit animation, we need to see about starting
// one.
@@ -2380,8 +2390,8 @@ public class WindowManagerService extends IWindowManager.Stub
win.updateLastInsetValues();
win.getCompatFrame(outFrame);
- win.getInsetsForRelayout(outOverscanInsets, outContentInsets, outVisibleInsets,
- outStableInsets, outOutsets);
+ win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
+ outStableInsets);
outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win));
@@ -2797,8 +2807,10 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void onPowerKeyDown(boolean isScreenOn) {
- mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
- DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn));
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn);
+ mRoot.forAllDisplayPolicies(c);
+ c.recycle();
}
@Override
@@ -3428,26 +3440,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private void updateCircularDisplayMaskIfNeeded() {
- if (mContext.getResources().getConfiguration().isScreenRound()
- && mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_windowShowCircularMask)) {
- final int currentUserId;
- synchronized (mGlobalLock) {
- currentUserId = mCurrentUserId;
- }
- // Device configuration calls for a circular display mask, but we only enable the mask
- // if the accessibility color inversion feature is disabled, as the inverted mask
- // causes artifacts.
- int inversionState = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId);
- int showMask = (inversionState == 1) ? 0 : 1;
- Message m = mH.obtainMessage(H.SHOW_CIRCULAR_DISPLAY_MASK);
- m.arg1 = showMask;
- mH.sendMessage(m);
- }
- }
-
public void showEmulatorDisplayOverlayIfNeeded() {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_windowEnableCircularEmulatorDisplayOverlay)
@@ -3457,35 +3449,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void showCircularMask(boolean visible) {
- synchronized (mGlobalLock) {
- if (visible) {
- // TODO(multi-display): support multiple displays
- if (mCircularDisplayMask == null) {
- int screenOffset = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_windowOutsetBottom);
- int maskThickness = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.circular_display_mask_thickness);
-
-
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG_WM,
- ">>> showCircularMask(visible=" + visible + ")");
- }
- mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory,
- getDefaultDisplayContentLocked(), mPolicy.getWindowLayerFromTypeLw(
- WindowManager.LayoutParams.TYPE_POINTER) * TYPE_LAYER_MULTIPLIER
- + 10, screenOffset, maskThickness, mTransaction);
- }
- mCircularDisplayMask.setVisibility(true, mTransaction);
- } else if (mCircularDisplayMask != null) {
- mCircularDisplayMask.setVisibility(false, mTransaction);
- mCircularDisplayMask = null;
- }
- mTransaction.apply();
- }
- }
-
public void showEmulatorDisplayOverlay() {
synchronized (mGlobalLock) {
@@ -3781,6 +3744,27 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+ }
+ try {
+ synchronized (mGlobalLock) {
+ if (mDisplayRotationController != null) {
+ mDisplayRotationController.asBinder().unlinkToDeath(
+ mDisplayRotationControllerDeath, 0);
+ mDisplayRotationController = null;
+ }
+ controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0);
+ mDisplayRotationController = controller;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Unable to set rotation controller");
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {
@@ -3944,6 +3928,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */
+ @Override
+ public void registerDisplayWindowListener(IDisplayWindowListener listener) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mDisplayNotificationController.registerListener(listener);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /** Unregister a hierarchy listener so that it stops receiving callbacks. */
+ @Override
+ public void unregisterDisplayWindowListener(IDisplayWindowListener listener) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_ACTIVITY_STACKS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
+ }
+ mDisplayNotificationController.unregisterListener(listener);
+ }
+
@Override
public int getPreferredOptionsPanelGravity(int displayId) {
synchronized (mGlobalLock) {
@@ -4436,8 +4445,6 @@ public class WindowManagerService extends IWindowManager.Stub
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
-
- updateCircularDisplayMaskIfNeeded();
}
public void systemReady() {
@@ -4520,7 +4527,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int NEW_ANIMATOR_SCALE = 34;
- public static final int SHOW_CIRCULAR_DISPLAY_MASK = 35;
public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
@@ -4754,11 +4760,6 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
- case SHOW_CIRCULAR_DISPLAY_MASK: {
- showCircularMask(msg.arg1 == 1);
- break;
- }
-
case SHOW_EMULATOR_DISPLAY_OVERLAY: {
showEmulatorDisplayOverlay();
break;
@@ -5168,38 +5169,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void setOverscan(int displayId, int left, int top, int right, int bottom) {
- if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- if (displayContent != null) {
- setOverscanLocked(displayContent, left, top, right, bottom);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void setOverscanLocked(DisplayContent displayContent,
- int left, int top, int right, int bottom) {
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- displayInfo.overscanLeft = left;
- displayInfo.overscanTop = top;
- displayInfo.overscanRight = right;
- displayInfo.overscanBottom = bottom;
-
- mDisplayWindowSettings.setOverscanLocked(displayInfo, left, top, right, bottom);
-
- displayContent.reconfigureDisplayLocked();
- }
-
- @Override
public void startWindowTrace(){
mWindowTracing.startTrace(null /* printwriter */);
}
@@ -5623,8 +5592,10 @@ public class WindowManagerService extends IWindowManager.Stub
+ android.Manifest.permission.STATUS_BAR);
}
synchronized (mGlobalLock) {
- mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
- DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show));
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show);
+ mRoot.forAllDisplayPolicies(c);
+ c.recycle();
}
}
@@ -7564,8 +7535,10 @@ public class WindowManagerService extends IWindowManager.Stub
void onLockTaskStateChanged(int lockTaskState) {
// TODO: pass in displayId to determine which display the lock task state changed
synchronized (mGlobalLock) {
- mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
- DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState));
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState);
+ mRoot.forAllDisplayPolicies(c);
+ c.recycle();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index e01cbf26dadc..8e955cf3a8bb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -66,8 +66,6 @@ public class WindowManagerShellCommand extends ShellCommand {
return runDisplayDensity(pw);
case "folded-area":
return runDisplayFoldedArea(pw);
- case "overscan":
- return runDisplayOverscan(pw);
case "scaling":
return runDisplayScaling(pw);
case "dismiss-keyguard":
@@ -247,30 +245,6 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
- private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
- String overscanStr = getNextArgRequired();
- Rect rect = new Rect();
- final int displayId = getDisplayId(overscanStr);
- if ("reset".equals(overscanStr)) {
- rect.set(0, 0, 0, 0);
- } else {
- final Pattern FLATTENED_PATTERN = Pattern.compile(
- "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
- Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
- if (!matcher.matches()) {
- getErrPrintWriter().println("Error: bad rectangle arg: " + overscanStr);
- return -1;
- }
- rect.left = Integer.parseInt(matcher.group(1));
- rect.top = Integer.parseInt(matcher.group(2));
- rect.right = Integer.parseInt(matcher.group(3));
- rect.bottom = Integer.parseInt(matcher.group(4));
- }
-
- mInterface.setOverscan(displayId, rect.left, rect.top, rect.right, rect.bottom);
- return 0;
- }
-
private int runDisplayScaling(PrintWriter pw) throws RemoteException {
String scalingStr = getNextArgRequired();
if ("auto".equals(scalingStr)) {
@@ -380,8 +354,6 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println(" Return or override display density.");
pw.println(" folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]");
pw.println(" Return or override folded area.");
- pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
- pw.println(" Set overscan area for display.");
pw.println(" scaling [off|auto] [-d DISPLAY_ID]");
pw.println(" Set display scaling mode.");
pw.println(" dismiss-keyguard");
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 7cf0beefa160..2e188b7cc86d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -165,7 +165,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// all activities running in the process
private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
// any tasks this process had run root activities in
- private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
+ private final ArrayList<Task> mRecentTasks = new ArrayList<>();
// The most recent top-most activity that was resumed in the process for pre-Q app.
private ActivityRecord mPreQTopResumedActivity = null;
// The last time an activity was launched in the process
@@ -533,7 +533,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
synchronized (mAtm.mGlobalLockWithoutBoost) {
for (int i = mActivities.size() - 1; i >= 0; --i) {
final ActivityRecord r = mActivities.get(i);
- if (r.visible) {
+ if (r.mVisibleRequested) {
return true;
}
}
@@ -550,12 +550,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private boolean hasActivityInVisibleTask() {
for (int i = mActivities.size() - 1; i >= 0; --i) {
- TaskRecord task = mActivities.get(i).getTaskRecord();
+ Task task = mActivities.get(i).getTask();
if (task == null) {
continue;
}
ActivityRecord topActivity = task.getTopActivity();
- if (topActivity != null && topActivity.visible) {
+ if (topActivity != null && topActivity.mVisibleRequested) {
return true;
}
}
@@ -589,7 +589,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// - no longer visible OR
// - not focusable (in PiP mode for instance)
if (topDisplay == null
- || !mPreQTopResumedActivity.visible
+ || !mPreQTopResumedActivity.mVisibleRequested
|| !mPreQTopResumedActivity.isFocusable()) {
canUpdate = true;
}
@@ -702,18 +702,18 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
ActivityRecord hist = mActivities.get(0);
intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName);
- intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTaskRecord().mTaskId);
+ intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTask().mTaskId);
}
- boolean shouldKillProcessForRemovedTask(TaskRecord tr) {
+ boolean shouldKillProcessForRemovedTask(Task task) {
for (int k = 0; k < mActivities.size(); k++) {
final ActivityRecord activity = mActivities.get(k);
if (!activity.stopped) {
// Don't kill process(es) that has an activity not stopped.
return false;
}
- final TaskRecord otherTask = activity.getTaskRecord();
- if (tr.mTaskId != otherTask.mTaskId && otherTask.inRecents) {
+ final Task otherTask = activity.getTask();
+ if (task.mTaskId != otherTask.mTaskId && otherTask.inRecents) {
// Don't kill process(es) that has an activity in a different task that is
// also in recents.
return false;
@@ -722,11 +722,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
- ArraySet<TaskRecord> getReleaseSomeActivitiesTasks() {
+ ArraySet<Task> getReleaseSomeActivitiesTasks() {
// Examine all activities currently running in the process.
- TaskRecord firstTask = null;
+ Task firstTask = null;
// Tasks is non-null only if two or more tasks are found.
- ArraySet<TaskRecord> tasks = null;
+ ArraySet<Task> tasks = null;
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
for (int i = 0; i < mActivities.size(); i++) {
final ActivityRecord r = mActivities.get(i);
@@ -739,13 +739,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
// Don't consider any activities that are currently not in a state where they
// can be destroyed.
- if (r.visible || !r.stopped || !r.hasSavedState()
+ if (r.mVisibleRequested || !r.stopped || !r.hasSavedState()
|| r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
if (task != null) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
+ " from " + r);
@@ -793,8 +793,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
continue;
}
}
- if (r.visible) {
- final TaskRecord task = r.getTaskRecord();
+ if (r.mVisibleRequested) {
+ final Task task = r.getTask();
if (task != null && minTaskLayer > 0) {
final int layer = task.mLayerRank;
if (layer >= 0 && minTaskLayer > layer) {
@@ -1023,11 +1023,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return (mListener != null) ? mListener.getCpuTime() : 0;
}
- void addRecentTask(TaskRecord task) {
+ void addRecentTask(Task task) {
mRecentTasks.add(task);
}
- void removeRecentTask(TaskRecord task) {
+ void removeRecentTask(Task task) {
mRecentTasks.remove(task);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d5905720a611..b8168319dd29 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1047,9 +1047,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
- // Calculate the outsets before the content frame gets shrinked to the window frame.
- mWindowFrames.calculateOutsets();
-
// Make sure the content and visible frames are inside of the
// final window frame.
if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) {
@@ -1094,13 +1091,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom));
}
- if (isFullscreenAndFillsDisplay && !windowsAreFloating) {
- // Windows that are not fullscreen can be positioned outside of the display frame,
- // but that is not a reason to provide them with overscan insets.
- InsetUtils.insetsBetweenFrames(layoutContainingFrame, mWindowFrames.mOverscanFrame,
- mWindowFrames.mOverscanInsets);
- }
-
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo(
mWindowFrames.mDisplayFrame);
@@ -1170,11 +1160,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
@Override
- public Rect getOverscanFrameLw() {
- return mWindowFrames.mOverscanFrame;
- }
-
- @Override
public Rect getContentFrameLw() {
return mWindowFrames.mContentFrame;
}
@@ -1554,7 +1539,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
// TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this?
boolean isWinVisibleLw() {
- return (mActivityRecord == null || !mActivityRecord.hiddenRequested
+ return (mActivityRecord == null || mActivityRecord.mVisibleRequested
|| mActivityRecord.isAnimating(TRANSITION)) && isVisible();
}
@@ -1563,7 +1548,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* not the pending requested hidden state.
*/
boolean isVisibleNow() {
- return (!mToken.isHidden() || mAttrs.type == TYPE_APPLICATION_STARTING)
+ return (mToken.isVisible() || mAttrs.type == TYPE_APPLICATION_STARTING)
&& isVisible();
}
@@ -1585,7 +1570,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final ActivityRecord atoken = mActivityRecord;
return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
&& isVisibleByPolicy() && !isParentWindowHidden()
- && (atoken == null || !atoken.hiddenRequested)
+ && (atoken == null || atoken.mVisibleRequested)
&& !mAnimatingExit && !mDestroying;
}
@@ -1600,7 +1585,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
final ActivityRecord atoken = mActivityRecord;
if (atoken != null) {
- return ((!isParentWindowHidden() && !atoken.hiddenRequested)
+ return ((!isParentWindowHidden() && atoken.mVisibleRequested)
|| isAnimating(TRANSITION | PARENTS));
}
return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
@@ -1636,7 +1621,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
final boolean parentAndClientVisible = !isParentWindowHidden()
- && mViewVisibility == View.VISIBLE && !mToken.isHidden();
+ && mViewVisibility == View.VISIBLE && mToken.isVisible();
return mHasSurface && isVisibleByPolicy() && !mDestroying
&& (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
}
@@ -1655,7 +1640,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
} else {
final Task task = getTask();
final boolean canFromTask = task != null && task.canAffectSystemUiFlags();
- return canFromTask && !mActivityRecord.isHidden();
+ return canFromTask && mActivityRecord.isVisible();
}
}
@@ -1667,7 +1652,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
public boolean isDisplayedLw() {
final ActivityRecord atoken = mActivityRecord;
return isDrawnLw() && isVisibleByPolicy()
- && ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested))
+ && ((!isParentWindowHidden() && (atoken == null || atoken.mVisibleRequested))
|| isAnimating(TRANSITION | PARENTS));
}
@@ -1684,8 +1669,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final ActivityRecord atoken = mActivityRecord;
return mViewVisibility == View.GONE
|| !mRelayoutCalled
- || (atoken == null && mToken.isHidden())
- || (atoken != null && atoken.hiddenRequested)
+ || (atoken == null && !mToken.isVisible())
+ || (atoken != null && !atoken.mVisibleRequested)
|| isParentWindowGoneForLayout()
|| (mAnimatingExit && !isAnimatingLw())
|| mDestroying;
@@ -2177,7 +2162,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " parentHidden=" + isParentWindowHidden()
+ " exiting=" + mAnimatingExit + " destroying=" + mDestroying);
if (mActivityRecord != null) {
- Slog.i(TAG_WM, " mActivityRecord.hiddenRequested=" + mActivityRecord.hiddenRequested);
+ Slog.i(TAG_WM, " mActivityRecord.visibleRequested="
+ + mActivityRecord.mVisibleRequested);
}
}
}
@@ -2588,7 +2574,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* interacts with it.
*/
private boolean shouldKeepVisibleDeadAppWindow() {
- if (!isWinVisibleLw() || mActivityRecord == null || mActivityRecord.isClientHidden()) {
+ if (!isWinVisibleLw() || mActivityRecord == null || !mActivityRecord.isClientVisible()) {
// Not a visible app window or the app isn't dead.
return false;
}
@@ -2625,14 +2611,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return showBecauseOfActivity || showBecauseOfWindow;
}
- /** @return false if this window desires touch events. */
+ /** @return {@code false} if this window desires touch events. */
boolean cantReceiveTouchInput() {
if (mActivityRecord == null || mActivityRecord.getTask() == null) {
return false;
}
return mActivityRecord.getTask().getTaskStack().shouldIgnoreInput()
- || mActivityRecord.hiddenRequested
+ || !mActivityRecord.mVisibleRequested
|| isAnimatingToRecents();
}
@@ -2900,13 +2886,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void sendAppVisibilityToClients() {
super.sendAppVisibilityToClients();
- final boolean clientHidden = mActivityRecord.isClientHidden();
- if (mAttrs.type == TYPE_APPLICATION_STARTING && clientHidden) {
+ final boolean clientVisible = mActivityRecord.isClientVisible();
+ if (mAttrs.type == TYPE_APPLICATION_STARTING && !clientVisible) {
// Don't hide the starting window.
return;
}
- if (clientHidden) {
+ if (!clientVisible) {
// Once we are notifying the client that it's visibility has changed, we need to prevent
// it from destroying child surfaces until the animation has finished. We do this by
// detaching any surface control the client added from the client.
@@ -2920,8 +2906,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
try {
if (DEBUG_VISIBILITY) Slog.v(TAG,
- "Setting visibility of " + this + ": " + (!clientHidden));
- mClient.dispatchAppVisibility(!clientHidden);
+ "Setting visibility of " + this + ": " + clientVisible);
+ mClient.dispatchAppVisibility(clientVisible);
} catch (RemoteException e) {
}
}
@@ -3265,11 +3251,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
final Rect frame = mWindowFrames.mCompatFrame;
- final Rect overscanInsets = mWindowFrames.mLastOverscanInsets;
final Rect contentInsets = mWindowFrames.mLastContentInsets;
final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
final Rect stableInsets = mWindowFrames.mLastStableInsets;
- final Rect outsets = mWindowFrames.mLastOutsets;
final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
final boolean reportOrientation = mReportOrientationChanged;
final int displayId = getDisplayId();
@@ -3281,8 +3265,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
public void run() {
try {
- dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
- stableInsets, outsets, reportDraw, mergedConfiguration,
+ dispatchResized(frame, contentInsets, visibleInsets,
+ stableInsets, reportDraw, mergedConfiguration,
reportOrientation, displayId, displayCutout);
} catch (RemoteException e) {
// Not a remote call, RemoteException won't be raised.
@@ -3290,8 +3274,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
});
} else {
- dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
+ dispatchResized(frame, contentInsets, visibleInsets, stableInsets,
+ reportDraw, mergedConfiguration, reportOrientation, displayId,
displayCutout);
}
if (mWmService.mAccessibilityController != null) {
@@ -3423,14 +3407,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return stack.mStackId;
}
- private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+ private void dispatchResized(Rect frame, Rect contentInsets,
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
DisplayCutout displayCutout)
throws RemoteException {
final boolean forceRelayout = isDragResizeChanged() || reportOrientation;
- mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+ mClient.resized(frame, contentInsets, visibleInsets, stableInsets,
reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this), displayId,
new DisplayCutout.ParcelableWrapper(displayCutout));
@@ -4163,9 +4147,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING)
+ " during animation: policyVis=" + isVisibleByPolicy()
+ " parentHidden=" + isParentWindowHidden()
- + " tok.hiddenRequested="
- + (mActivityRecord != null && mActivityRecord.hiddenRequested)
- + " tok.hidden=" + (mActivityRecord != null && mActivityRecord.isHidden())
+ + " tok.visibleRequested="
+ + (mActivityRecord != null && mActivityRecord.mVisibleRequested)
+ + " tok.visible=" + (mActivityRecord != null && mActivityRecord.isVisible())
+ " animating=" + isAnimating(TRANSITION | PARENTS)
+ " tok animating="
+ (mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION))
@@ -4572,7 +4556,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " pv=" + isVisibleByPolicy()
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
- + " th=" + (mActivityRecord != null ? mActivityRecord.hiddenRequested : false)
+ + " th=" + (mActivityRecord != null && mActivityRecord.mVisibleRequested)
+ " a=" + isAnimating(TRANSITION | PARENTS));
}
}
@@ -5282,13 +5266,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* Copy the inset values over so they can be sent back to the client when a relayout occurs.
*/
- void getInsetsForRelayout(Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
- Rect outStableInsets, Rect outOutsets) {
- outOverscanInsets.set(mWindowFrames.mOverscanInsets);
+ void getInsetsForRelayout(Rect outContentInsets, Rect outVisibleInsets,
+ Rect outStableInsets) {
outContentInsets.set(mWindowFrames.mContentInsets);
outVisibleInsets.set(mWindowFrames.mVisibleInsets);
outStableInsets.set(mWindowFrames.mStableInsets);
- outOutsets.set(mWindowFrames.mOutsets);
mLastRelayoutContentInsets.set(mWindowFrames.mContentInsets);
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 88a1458a783f..6480a15a4220 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -29,7 +29,6 @@ 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.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowTokenProto.HASH_CODE;
-import static com.android.server.wm.WindowTokenProto.HIDDEN;
import static com.android.server.wm.WindowTokenProto.PAUSED;
import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
import static com.android.server.wm.WindowTokenProto.WINDOWS;
@@ -72,9 +71,6 @@ class WindowToken extends WindowContainer<WindowState> {
// Is key dispatching paused for this token?
boolean paused = false;
- // Should this token's windows be hidden?
- private boolean mHidden;
-
// Temporary for finding which tokens no longer have visible windows.
boolean hasVisible;
@@ -128,16 +124,6 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
- void setHidden(boolean hidden) {
- if (hidden != mHidden) {
- mHidden = hidden;
- }
- }
-
- boolean isHidden() {
- return mHidden;
- }
-
void removeAllWindowsIfPossible() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState win = mChildren.get(i);
@@ -156,7 +142,7 @@ class WindowToken extends WindowContainer<WindowState> {
// This token is exiting, so allow it to be removed when it no longer contains any windows.
mPersistOnEmpty = false;
- if (mHidden) {
+ if (!isVisible()) {
return;
}
@@ -169,7 +155,10 @@ class WindowToken extends WindowContainer<WindowState> {
changed |= win.onSetAppExiting();
}
- setHidden(true);
+ final ActivityRecord app = asActivityRecord();
+ if (app != null) {
+ app.setVisible(false);
+ }
if (changed) {
mWmService.mWindowPlacerLocked.performSurfacePlacement();
@@ -286,7 +275,6 @@ class WindowToken extends WindowContainer<WindowState> {
final WindowState w = mChildren.get(i);
w.writeToProto(proto, WINDOWS, logLevel);
}
- proto.write(HIDDEN, mHidden);
proto.write(WAITING_TO_SHOW, waitingToShow);
proto.write(PAUSED, paused);
proto.end(token);
@@ -296,8 +284,7 @@ class WindowToken extends WindowContainer<WindowState> {
super.dump(pw, prefix, dumpAll);
pw.print(prefix); pw.print("windows="); pw.println(mChildren);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
- pw.print(" hidden="); pw.print(mHidden);
- pw.print(" hasVisible="); pw.println(hasVisible);
+ pw.print(" hasVisible="); pw.println(hasVisible);
if (waitingToShow || sendingToBottom) {
pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
pw.print(" sendingToBottom="); pw.print(sendingToBottom);
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 91c05a858ce4..bffa44e868a7 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -4,6 +4,7 @@ java_library_static {
libs: [
"services.core",
+ "app-compat-annotations",
],
plugins: [
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a39cc2088be0..9dac03f633dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4928,21 +4928,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
@PasswordComplexity
- public int getPasswordComplexity() {
+ public int getPasswordComplexity(boolean parent) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.GET_USER_PASSWORD_COMPLEXITY_LEVEL)
.setStrings(mInjector.getPackageManager()
.getPackagesForUid(mInjector.binderGetCallingUid()))
.write();
final int callingUserId = mInjector.userHandleGetCallingUserId();
+
+ if (parent) {
+ enforceProfileOwnerOrSystemUser();
+ }
enforceUserUnlocked(callingUserId);
mContext.enforceCallingOrSelfPermission(
REQUEST_PASSWORD_COMPLEXITY,
"Must have " + REQUEST_PASSWORD_COMPLEXITY + " permission.");
synchronized (getLockObject()) {
- int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false);
- PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(targetUserId);
+ final int credentialOwner = getCredentialOwner(callingUserId, parent);
+ PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 597d337c2450..99dd9a12eb72 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -44,6 +44,7 @@ import android.os.UserHandle;
import android.testing.DexmakerShareClassLoaderRule;
import android.view.Display;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
@@ -80,6 +81,7 @@ public class AccessibilityServiceConnectionTest {
@Mock ResolveInfo mMockResolveInfo;
@Mock AccessibilitySecurityPolicy mMockSecurityPolicy;
@Mock AccessibilityWindowManager mMockA11yWindowManager;
+ @Mock ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
@Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock SystemActionPerformer mMockSystemActionPerformer;
@@ -111,7 +113,8 @@ public class AccessibilityServiceConnectionTest {
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
- mMockSystemActionPerformer, mMockA11yWindowManager);
+ mMockSystemActionPerformer, mMockA11yWindowManager,
+ mMockActivityTaskManagerInternal);
when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
new file mode 100644
index 000000000000..2e2270bc6ef5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.content;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import android.content.Context;
+import android.content.SyncStatusInfo;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * Tests for {@link SyncStorageEngine}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SyncStorageEngineTest {
+
+ private Context mContext;
+ private SyncStorageEngine mSyncStorageEngine;
+
+ private static final int NUM_SYNC_STATUS = 100;
+ private static final int NUM_PERIODIC_SYNC_TIMES = 20;
+ private static final int NUM_EVENTS = 10;
+ private static final int NUM_SOURCES = 6;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mSyncStorageEngine = SyncStorageEngine.newTestInstance(mContext);
+ }
+
+ @Test
+ public void testStatisticsReadWrite() {
+ populateDayStats(mSyncStorageEngine.mDayStats);
+ mSyncStorageEngine.writeStatisticsLocked();
+
+ final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
+ verifyDayStats(mSyncStorageEngine.mDayStats, other.getDayStatistics());
+ }
+
+ @Test
+ public void testStatusReadWrite() {
+ populateStatus(mSyncStorageEngine.mSyncStatus);
+ mSyncStorageEngine.writeStatusLocked();
+
+ final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
+ for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+ other.mAuthorities.put(i, null);
+ }
+ other.readStatusLocked();
+ verifyStatus(mSyncStorageEngine.mSyncStatus, other.mSyncStatus);
+ }
+
+ private void populateDayStats(SyncStorageEngine.DayStats[] dayStats) {
+ final Random r = new Random(1);
+ for (int i = 0; i < dayStats.length; i++) {
+ final SyncStorageEngine.DayStats ds = new SyncStorageEngine.DayStats(i);
+ ds.successCount = r.nextInt();
+ ds.successTime = r.nextLong();
+ ds.failureCount = r.nextInt();
+ ds.failureTime = r.nextLong();
+ dayStats[i] = ds;
+ }
+ }
+
+ private void verifyDayStats(SyncStorageEngine.DayStats[] dayStats,
+ SyncStorageEngine.DayStats[] dayStatsOther) {
+ assertEquals(dayStatsOther.length, dayStats.length);
+ for (int i = 0; i < dayStatsOther.length; i++) {
+ final SyncStorageEngine.DayStats ds = dayStats[i];
+ final SyncStorageEngine.DayStats dsOther = dayStatsOther[i];
+ assertEquals(dsOther.day, ds.day);
+ assertEquals(dsOther.successCount, ds.successCount);
+ assertEquals(dsOther.successTime, ds.successTime);
+ assertEquals(dsOther.failureCount, ds.failureCount);
+ assertEquals(dsOther.failureTime, ds.failureTime);
+ }
+ }
+
+ private void populateStatus(SparseArray<SyncStatusInfo> syncStatus) {
+ final Random r = new Random(1);
+ for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+ final SyncStatusInfo ss = new SyncStatusInfo(i);
+ ss.lastSuccessTime = r.nextLong();
+ ss.lastSuccessSource = r.nextInt();
+ ss.lastFailureTime = r.nextLong();
+ ss.lastFailureSource = r.nextInt();
+ ss.lastFailureMesg = "fail_msg_" + r.nextInt();
+ ss.initialFailureTime = r.nextLong();
+ ss.initialize = r.nextBoolean();
+ for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
+ ss.addPeriodicSyncTime(r.nextLong());
+ }
+ final ArrayList<Pair<Long, String>> lastEventInfos = new ArrayList<>();
+ for (int j = 0; j < NUM_EVENTS; j++) {
+ lastEventInfos.add(new Pair<>(r.nextLong(), "event_" + r.nextInt()));
+ }
+ ss.populateLastEventsInformation(lastEventInfos);
+ ss.lastTodayResetTime = r.nextLong();
+ populateStats(ss.totalStats, r);
+ populateStats(ss.todayStats, r);
+ populateStats(ss.yesterdayStats, r);
+ for (int j = 0; j < NUM_SOURCES; j++) {
+ ss.perSourceLastSuccessTimes[j] = r.nextLong();
+ }
+ for (int j = 0; j < NUM_SOURCES; j++) {
+ ss.perSourceLastFailureTimes[j] = r.nextLong();
+ }
+ syncStatus.put(i, ss);
+ }
+ }
+
+ private void populateStats(SyncStatusInfo.Stats stats, Random r) {
+ stats.totalElapsedTime = r.nextLong();
+ stats.numSyncs = r.nextInt();
+ stats.numFailures = r.nextInt();
+ stats.numCancels = r.nextInt();
+ stats.numSourceOther = r.nextInt();
+ stats.numSourceLocal = r.nextInt();
+ stats.numSourcePoll = r.nextInt();
+ stats.numSourceUser = r.nextInt();
+ stats.numSourcePeriodic = r.nextInt();
+ stats.numSourceFeed = r.nextInt();
+ }
+
+ private void verifyStatus(SparseArray<SyncStatusInfo> syncStatus,
+ SparseArray<SyncStatusInfo> syncStatusOther) {
+ assertEquals(syncStatusOther.size(), syncStatus.size());
+ for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+ final SyncStatusInfo ss = syncStatus.valueAt(i);
+ final SyncStatusInfo ssOther = syncStatusOther.valueAt(i);
+ assertEquals(ssOther.authorityId, ss.authorityId);
+ assertEquals(ssOther.lastSuccessTime, ss.lastSuccessTime);
+ assertEquals(ssOther.lastSuccessSource, ss.lastSuccessSource);
+ assertEquals(ssOther.lastFailureTime, ss.lastFailureTime);
+ assertEquals(ssOther.lastFailureSource, ss.lastFailureSource);
+ assertEquals(ssOther.lastFailureMesg, ss.lastFailureMesg);
+ assertFalse(ssOther.pending); // pending is always set to false when read
+ assertEquals(ssOther.initialize, ss.initialize);
+ assertEquals(ssOther.getPeriodicSyncTimesSize(), NUM_PERIODIC_SYNC_TIMES);
+ for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
+ assertEquals(ssOther.getPeriodicSyncTime(j), ss.getPeriodicSyncTime(j));
+ }
+ assertEquals(ssOther.getEventCount(), NUM_EVENTS);
+ for (int j = 0; j < NUM_EVENTS; j++) {
+ assertEquals(ssOther.getEventTime(j), ss.getEventTime(j));
+ assertEquals(ssOther.getEvent(j), ss.getEvent(j));
+ }
+ assertEquals(ssOther.lastTodayResetTime, ss.lastTodayResetTime);
+ verifyStats(ss.totalStats, ssOther.totalStats);
+ verifyStats(ss.todayStats, ssOther.todayStats);
+ verifyStats(ss.yesterdayStats, ssOther.yesterdayStats);
+ assertEquals(ssOther.perSourceLastSuccessTimes.length, NUM_SOURCES);
+ for (int j = 0; j < NUM_SOURCES; j++) {
+ assertEquals(ssOther.perSourceLastSuccessTimes[j], ss.perSourceLastSuccessTimes[j]);
+ }
+ assertEquals(ssOther.perSourceLastFailureTimes.length, NUM_SOURCES);
+ for (int j = 0; j < NUM_SOURCES; j++) {
+ assertEquals(ssOther.perSourceLastFailureTimes[j], ss.perSourceLastFailureTimes[j]);
+ }
+ }
+ }
+
+ private void verifyStats(SyncStatusInfo.Stats stats, SyncStatusInfo.Stats statsOther) {
+ assertEquals(statsOther.totalElapsedTime, stats.totalElapsedTime);
+ assertEquals(statsOther.numSyncs, stats.numSyncs);
+ assertEquals(statsOther.numFailures, stats.numFailures);
+ assertEquals(statsOther.numCancels, stats.numCancels);
+ assertEquals(statsOther.numSourceOther, stats.numSourceOther);
+ assertEquals(statsOther.numSourceLocal, stats.numSourceLocal);
+ assertEquals(statsOther.numSourcePoll, stats.numSourcePoll);
+ assertEquals(statsOther.numSourceUser, stats.numSourceUser);
+ assertEquals(statsOther.numSourcePeriodic, stats.numSourcePeriodic);
+ assertEquals(statsOther.numSourceFeed, stats.numSourceFeed);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f571411391b5..f270724cca0c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5295,13 +5295,17 @@ public class DevicePolicyManagerTest extends DpmTestBase {
});
}
- public void testGetPasswordComplexity_securityExceptionIfParentInstance() {
- assertThrows(SecurityException.class,
- () -> new DevicePolicyManagerTestable(
- mServiceContext,
- dpms,
- /* parentInstance= */ true)
- .getPasswordComplexity());
+ public void testGetPasswordComplexity_securityExceptionNotThrownForParentInstance() {
+ mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
+ setAsProfileOwner(admin1);
+
+ new DevicePolicyManagerTestable(
+ mServiceContext,
+ dpms,
+ /* parentInstance= */ true)
+ .getPasswordComplexity();
+
+ assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity());
}
public void testGetPasswordComplexity_illegalStateExceptionIfLocked() {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
index 86e544d409fe..975689db5264 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -18,9 +18,10 @@ package com.android.server.integrity.parser;
import static com.android.server.testutils.TestUtils.assertExpectException;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
import org.junit.Test;
@@ -29,86 +30,416 @@ import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
@RunWith(JUnit4.class)
public class RuleXmlParserTest {
- private static final String VALID_RULE_XML = "<RuleList>"
- + "<Rule>"
- + "<OpenFormula>"
- + "<Connector>NOT</Connector>"
- + "<AtomicFormula>"
- + "<Key>PACKAGE_NAME</Key>"
- + "<Operator>EQ</Operator>"
- + "<Value>com.app.test</Value>"
- + "</AtomicFormula>"
- + "</OpenFormula>"
- + "<Effect>DENY</Effect>"
- + "</Rule>"
- + "</RuleList>";
+ @Test
+ public void testXmlStream_validOpenFormula() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ InputStream inputStream = new ByteArrayInputStream(ruleXmlOpenFormula.getBytes());
+ Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(inputStream);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
@Test
- public void testXmlString_validRule() {
+ public void testXmlString_validOpenFormula_notConnector() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+ Rule.DENY);
- List<Rule> rules = xmlParser.parse(VALID_RULE_XML);
+ List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
- assertNotNull(rules);
- assertTrue(rules.isEmpty());
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testXmlStream_validRule() {
+ public void testXmlString_validOpenFormula_andConnector() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.AND + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>test_cert</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- InputStream inputStream = new ByteArrayInputStream(VALID_RULE_XML.getBytes());
+ Rule expectedRule = new Rule(new OpenFormula(OpenFormula.AND, Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
+ Rule.DENY);
- List<Rule> rules = xmlParser.parse(inputStream);
+ List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_validOpenFormula_orConnector() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.OR + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>test_cert</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(new OpenFormula(OpenFormula.OR, Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_validOpenFormula_differentTagOrder() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_invalidOpenFormula_invalidNumberOfFormulas() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>1</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
+ () -> xmlParser.parse(ruleXmlOpenFormula));
+ }
+
+ @Test
+ public void testXmlString_invalidOpenFormula_invalidOperator() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>INVALID_OPERATOR</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
- assertNotNull(rules);
- assertTrue(rules.isEmpty());
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "For input string: \"INVALID_OPERATOR\"",
+ () -> xmlParser.parse(ruleXmlOpenFormula));
+ }
+
+ @Test
+ public void testXmlString_invalidOpenFormula_invalidEffect() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>INVALID_EFFECT</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "For input string: \"INVALID_EFFECT\"",
+ () -> xmlParser.parse(ruleXmlOpenFormula));
+ }
+
+ @Test
+ public void testXmlString_invalidOpenFormula_invalidTags() throws Exception {
+ String ruleXmlOpenFormula = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<InvalidConnector>" + OpenFormula.NOT + "</InvalidConnector>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidConnector",
+ () -> xmlParser.parse(ruleXmlOpenFormula));
+ }
+
+ @Test
+ public void testXmlString_validAtomicFormula_stringValue() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_validAtomicFormula_integerValue() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>1</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(
+ new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_validAtomicFormula_booleanValue() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>true</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(
+ new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_validAtomicFormula_differentTagOrder() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+ Rule expectedRule = new Rule(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+
+ assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+ }
+
+ @Test
+ public void testXmlString_invalidAtomicFormula_invalidTags() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<BadKey>" + AtomicFormula.PACKAGE_NAME + "</BadKey>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "Found unexpected tag: BadKey",
+ () -> xmlParser.parse(ruleXmlAtomicFormula));
+ }
+
+ @Test
+ public void testXmlString_invalidAtomicFormula() throws Exception {
+ String ruleXmlAtomicFormula = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+ RuleParser xmlParser = new RuleXmlParser();
+
+ assertExpectException(
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "For input string: \"com.app.test\"",
+ () -> xmlParser.parse(ruleXmlAtomicFormula));
}
@Test
public void testXmlString_withNoRuleList() {
- String ruleXmlWithNoRuleList = "<Rule>"
- + "<OpenFormula>"
- + "<Connector>NOT</Connector>"
- + "<AtomicFormula>"
- + "<Key>PACKAGE_NAME</Key>"
- + "<Operator>EQ</Operator>"
- + "<Value>com.app.test</Value>"
- + "</AtomicFormula>"
- + "</OpenFormula>"
- + "<Effect>DENY</Effect>"
- + "</Rule>";
+ String ruleXmlWithNoRuleList = "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
- RuntimeException.class,
- /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
() -> xmlParser.parse(ruleXmlWithNoRuleList));
}
@Test
public void testXmlStream_withNoRuleList() {
- String ruleXmlWithNoRuleList = "<Rule>"
- + "<OpenFormula>"
- + "<Connector>NOT</Connector>"
- + "<AtomicFormula>"
- + "<Key>PACKAGE_NAME</Key>"
- + "<Operator>EQ</Operator>"
- + "<Value>com.app.test</Value>"
- + "</AtomicFormula>"
- + "</OpenFormula>"
- + "<Effect>DENY</Effect>"
- + "</Rule>";
+ String ruleXmlWithNoRuleList = "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>";
InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
- RuntimeException.class,
- /* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
+ RuleParseException.class,
+ /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
() -> xmlParser.parse(inputStream));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
new file mode 100644
index 000000000000..082fda82499a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.serializer;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.integrity.model.AppInstallMetadata;
+import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.Formula;
+import com.android.server.integrity.model.OpenFormula;
+import com.android.server.integrity.model.Rule;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(JUnit4.class)
+public class RuleXmlSerializerTest {
+
+ @Test
+ public void testXmlString_serializeEmptyRule() throws Exception {
+ Rule rule = null;
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL />";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
+ Rule rule1 = null;
+ Rule rule2 = new Rule(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Arrays.asList(rule1, rule2));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlStream_serializeValidOpenFormula() throws Exception {
+ Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+ "com.app.test"))), Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ OutputStream outputStream = new ByteArrayOutputStream();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ xmlSerializer.serialize(Collections.singletonList(rule), outputStream);
+
+ String actualRules = outputStream.toString();
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidOpenFormula_notConnector() throws Exception {
+ Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+ "com.app.test"))), Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.NOT + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidOpenFormula_andConnector() throws Exception {
+ Rule rule = new Rule(new OpenFormula(OpenFormula.AND,
+ Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+ "com.app.test"),
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
+ "test_cert"))), Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.AND + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+ + "<V>test_cert</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidOpenFormula_orConnector() throws Exception {
+ Rule rule = new Rule(new OpenFormula(OpenFormula.OR,
+ Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
+ "com.app.test"),
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
+ "test_cert"))), Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<OF>"
+ + "<C>" + OpenFormula.OR + "</C>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.APP_CERTIFICATE + "</K>"
+ + "<V>test_cert</V>"
+ + "</AF>"
+ + "</OF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidAtomicFormula_stringValue() throws Exception {
+ Rule rule = new Rule(
+ new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
+ Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PACKAGE_NAME + "</K>"
+ + "<V>com.app.test</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception {
+ Rule rule = new Rule(
+ new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+ Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.VERSION_CODE + "</K>"
+ + "<O>" + AtomicFormula.EQ + "</O>"
+ + "<V>1</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeValidAtomicFormula_booleanValue() throws Exception {
+ Rule rule = new Rule(
+ new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+ Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+ String expectedRules = "<RL>"
+ + "<R>"
+ + "<AF>"
+ + "<K>" + AtomicFormula.PRE_INSTALLED + "</K>"
+ + "<V>true</V>"
+ + "</AF>"
+ + "<E>" + Rule.DENY + "</E>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+
+ assertEquals(expectedRules, actualRules);
+ }
+
+ @Test
+ public void testXmlString_serializeInvalidFormulaType() throws Exception {
+ Formula invalidFormula = getInvalidFormula();
+ Rule rule = new Rule(invalidFormula, Rule.DENY);
+ RuleSerializer xmlSerializer = new RuleXmlSerializer();
+
+ assertExpectException(
+ RuleSerializeException.class,
+ /* expectedExceptionMessageRegex */ "Invalid formula type",
+ () -> xmlSerializer.serialize(Collections.singletonList(rule)));
+ }
+
+ private Formula getInvalidFormula() {
+ return new Formula() {
+ @Override
+ public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ @NonNull
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ }
+ };
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 3c1044728fcc..b751308a4bb4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -156,6 +156,8 @@ public class PackageInstallerSessionTest {
if (isMultiPackage) {
params.isMultiPackage = true;
}
+ InstallSource installSource = InstallSource.create("testInstaller", null, "testInstaller",
+ false);
return new PackageInstallerSession(
/* callback */ null,
/* context */null,
@@ -166,7 +168,7 @@ public class PackageInstallerSessionTest {
/* sessionId */ sessionId,
/* userId */ 456,
/* installerUid */ -1,
- /* installSource */ InstallSource.create("testInstaller", "testInstaller"),
+ /* installSource */ installSource,
/* sessionParams */ params,
/* createdMillis */ 0L,
/* stageDir */ mTmpDir,
diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
deleted file mode 100644
index d1ac19c540a4..000000000000
--- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
+++ /dev/null
@@ -1,141 +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.server.stats;
-
-import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline;
-import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
-
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-
-/**
- * Build/Install/Run:
- * atest FrameworksServicesTests:ProcfsMemoryUtilTest
- */
-@SmallTest
-public class ProcfsMemoryUtilTest {
- private static final String STATUS_CONTENTS = "Name:\tandroid.youtube\n"
- + "State:\tS (sleeping)\n"
- + "Tgid:\t12088\n"
- + "Pid:\t12088\n"
- + "PPid:\t723\n"
- + "TracerPid:\t0\n"
- + "Uid:\t10083\t10083\t10083\t10083\n"
- + "Gid:\t10083\t10083\t10083\t10083\n"
- + "Ngid:\t0\n"
- + "FDSize:\t128\n"
- + "Groups:\t3003 9997 20083 50083 \n"
- + "VmPeak:\t 4546844 kB\n"
- + "VmSize:\t 4542636 kB\n"
- + "VmLck:\t 0 kB\n"
- + "VmPin:\t 0 kB\n"
- + "VmHWM:\t 137668 kB\n" // RSS high-water mark
- + "VmRSS:\t 126776 kB\n" // RSS
- + "RssAnon:\t 37860 kB\n"
- + "RssFile:\t 88764 kB\n"
- + "RssShmem:\t 152 kB\n"
- + "VmData:\t 4125112 kB\n"
- + "VmStk:\t 8192 kB\n"
- + "VmExe:\t 24 kB\n"
- + "VmLib:\t 102432 kB\n"
- + "VmPTE:\t 1300 kB\n"
- + "VmPMD:\t 36 kB\n"
- + "VmSwap:\t 22 kB\n" // Swap
- + "Threads:\t95\n"
- + "SigQ:\t0/13641\n"
- + "SigPnd:\t0000000000000000\n"
- + "ShdPnd:\t0000000000000000\n"
- + "SigBlk:\t0000000000001204\n"
- + "SigIgn:\t0000000000000001\n"
- + "SigCgt:\t00000006400084f8\n"
- + "CapInh:\t0000000000000000\n"
- + "CapPrm:\t0000000000000000\n"
- + "CapEff:\t0000000000000000\n"
- + "CapBnd:\t0000000000000000\n"
- + "CapAmb:\t0000000000000000\n"
- + "Seccomp:\t2\n"
- + "Cpus_allowed:\tff\n"
- + "Cpus_allowed_list:\t0-7\n"
- + "Mems_allowed:\t1\n"
- + "Mems_allowed_list:\t0\n"
- + "voluntary_ctxt_switches:\t903\n"
- + "nonvoluntary_ctxt_switches:\t104\n";
-
- @Test
- public void testParseMemorySnapshotFromStatus_parsesCorrectValue() {
- MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS);
- assertThat(snapshot.uid).isEqualTo(10083);
- assertThat(snapshot.rssHighWaterMarkInKilobytes).isEqualTo(137668);
- assertThat(snapshot.rssInKilobytes).isEqualTo(126776);
- assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860);
- assertThat(snapshot.swapInKilobytes).isEqualTo(22);
- }
-
- @Test
- public void testParseMemorySnapshotFromStatus_invalidValue() {
- MemorySnapshot snapshot =
- parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest");
- assertThat(snapshot).isNull();
- }
-
- @Test
- public void testParseMemorySnapshotFromStatus_emptyContents() {
- MemorySnapshot snapshot = parseMemorySnapshotFromStatus("");
- assertThat(snapshot).isNull();
- }
-
- @Test
- public void testParseCmdline_invalidValue() {
- byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
-
- assertThat(parseCmdline(bytesToString(nothing))).isEmpty();
- }
-
- @Test
- public void testParseCmdline_correctValue_noNullBytes() {
- assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app");
- }
-
- @Test
- public void testParseCmdline_correctValue_withNullBytes() {
- byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
-
- assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
-
- // test\0\0test
- byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
-
- assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
- }
-
- @Test
- public void testParseCmdline_emptyContents() {
- assertThat(parseCmdline("")).isEmpty();
- }
-
- private static String bytesToString(byte[] bytes) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- output.write(bytes, 0, bytes.length);
- return output.toString();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 36504ac7ec65..4a13dce5642b 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.app.usage.UsageStatsManager;
import android.os.FileUtils;
import android.test.AndroidTestCase;
@@ -150,4 +149,21 @@ public class AppIdleHistoryTests extends AndroidTestCase {
aih = new AppIdleHistory(mStorageDir, 5000);
assertEquals(REASON_MAIN_TIMEOUT, aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000));
}
+
+ public void testNullPackage() throws Exception {
+ AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
+ // Report usage of a package
+ aih.reportUsage(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0);
+ // "Accidentally" report usage against a null named package
+ aih.reportUsage(null, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0);
+ // Persist data
+ aih.writeAppIdleTimes(USER_ID);
+ // Recover data from disk
+ aih = new AppIdleHistory(mStorageDir, 5000);
+ // Verify data is intact
+ assertEquals(REASON_MAIN_USAGE | REASON_SUB_USAGE_MOVE_TO_FOREGROUND,
+ aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000));
+ }
} \ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index bcff2f81f805..608625f9fd10 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -18,6 +18,7 @@ package com.android.server.notification;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -25,7 +26,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
import android.app.NotificationHistory.HistoricalNotification;
+import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.util.AtomicFile;
@@ -42,8 +45,17 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
@@ -51,6 +63,11 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
File mRootDir;
@Mock
Handler mFileWriteHandler;
+ @Mock
+ Context mContext;
+ @Mock
+ AlarmManager mAlarmManager;
+ TestFileAttrProvider mFileAttrProvider;
NotificationHistoryDatabase mDataBase;
@@ -85,36 +102,56 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+ when(mContext.getUser()).thenReturn(getContext().getUser());
+ when(mContext.getPackageName()).thenReturn(getContext().getPackageName());
+ mFileAttrProvider = new TestFileAttrProvider();
mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest");
- mDataBase = new NotificationHistoryDatabase(mRootDir);
+ mDataBase = new NotificationHistoryDatabase(mContext, mRootDir, mFileAttrProvider);
mDataBase.init(mFileWriteHandler);
}
@Test
- public void testPrune() {
+ public void testDeletionReceiver() {
+ verify(mContext, times(1)).registerReceiver(any(), any());
+ }
+
+ @Test
+ public void testPrune() throws Exception {
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.setTimeInMillis(10);
int retainDays = 1;
- for (long i = 10; i >= 5; i--) {
+
+ List<AtomicFile> expectedFiles = new ArrayList<>();
+
+ // add 5 files with a creation date of "today"
+ for (long i = cal.getTimeInMillis(); i >= 5; i--) {
File file = mock(File.class);
- when(file.lastModified()).thenReturn(i);
+ mFileAttrProvider.creationDates.put(file, i);
AtomicFile af = new AtomicFile(file);
+ expectedFiles.add(af);
mDataBase.mHistoryFiles.addLast(af);
}
- GregorianCalendar cal = new GregorianCalendar();
- cal.setTimeInMillis(5);
+
cal.add(Calendar.DATE, -1 * retainDays);
+ // Add 5 more files more than retainDays old
for (int i = 5; i >= 0; i--) {
File file = mock(File.class);
- when(file.lastModified()).thenReturn(cal.getTimeInMillis() - i);
+ mFileAttrProvider.creationDates.put(file, cal.getTimeInMillis() - i);
AtomicFile af = new AtomicFile(file);
mDataBase.mHistoryFiles.addLast(af);
}
- mDataBase.prune(retainDays, 10);
- for (AtomicFile file : mDataBase.mHistoryFiles) {
- assertThat(file.getBaseFile().lastModified() > 0);
- }
+ // back to today; trim everything a day + old
+ cal.add(Calendar.DATE, 1 * retainDays);
+ mDataBase.prune(retainDays, cal.getTimeInMillis());
+
+ assertThat(mDataBase.mHistoryFiles).containsExactlyElementsIn(expectedFiles);
+
+ verify(mAlarmManager, times(6)).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
+
}
@Test
@@ -181,4 +218,12 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
verify(af2, never()).openRead();
}
+ private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider {
+ public Map<File, Long> creationDates = new HashMap<>();
+
+ @Override
+ public long getCreationTime(File file) {
+ return creationDates.get(file);
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 776c00e75846..8961796ed617 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2417,6 +2417,24 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void testLockChannelsForOEM_channelSpecific_clearData() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.getImportance(PKG_O, UID_O);
+ mHelper.lockChannelsForOEM(new String[] {PKG_O + ":" + a.getId()});
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByOEM());
+
+ mHelper.clearData(PKG_O, UID_O);
+
+ // it's back!
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ // and still locked
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
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 4daf6d3e601e..e560cb9a6cf7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -93,7 +93,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
// Create a pinned stack and move to front.
final ActivityStack pinnedStack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor)
+ final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor)
.setStack(pinnedStack).build();
new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
.setTask(pinnedTask).build();
@@ -167,7 +167,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
final ActivityStack fullscreenStack = display.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
+ final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
.setStack(fullscreenStack).build();
new ActivityBuilder(mService).setTask(fullscreenTask).build();
return fullscreenStack;
@@ -302,18 +302,10 @@ public class ActivityDisplayTests extends ActivityTestsBase {
ACTIVITY_TYPE_STANDARD, ON_TOP);
final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor)
- .setStack(stack1)
- .build();
- final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
- .setStack(stack2)
- .build();
- final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor)
- .setStack(stack3)
- .build();
- final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor)
- .setStack(stack4)
- .build();
+ final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build();
+ final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build();
+ final Task task3 = new TaskBuilder(mService.mStackSupervisor).setStack(stack3).build();
+ final Task task4 = new TaskBuilder(mService.mStackSupervisor).setStack(stack4).build();
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
@@ -354,7 +346,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
activity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
activity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- activity.visible = true;
+ activity.mVisibleRequested = true;
activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
final ArrayList<CompletableFuture<IBinder>> resultWrapper = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 44cacd821355..734761fd8048 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -78,7 +78,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
// This seems to be the easiest way to create an ActivityRecord.
mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
mTopActivity = new ActivityBuilder(mService)
- .setTask(mTrampolineActivity.getTaskRecord())
+ .setTask(mTrampolineActivity.getTask())
.build();
}
@@ -160,7 +160,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
public void testOnActivityLaunchCancelled_hasDrawn() {
onActivityLaunched();
- mTopActivity.visible = mTopActivity.mDrawn = true;
+ mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
// Cannot time already-visible activities.
mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
@@ -171,13 +171,13 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
@Test
public void testOnActivityLaunchCancelled_finishedBeforeDrawn() {
- mTopActivity.visible = mTopActivity.mDrawn = true;
+ mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
// Suppress resume when creating the record because we want to notify logger manually.
mSupervisor.beginDeferResume();
// Create an activity with different process that meets process switch.
final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
- .setTask(mTopActivity.getTaskRecord())
+ .setTask(mTopActivity.getTask())
.setProcessName("other")
.build();
mSupervisor.readyToResume();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index ac1048277849..e22c419f5919 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -113,7 +113,7 @@ import org.mockito.invocation.InvocationOnMock;
@RunWith(WindowTestRunner.class)
public class ActivityRecordTests extends ActivityTestsBase {
private ActivityStack mStack;
- private TaskRecord mTask;
+ private Task mTask;
private ActivityRecord mActivity;
@Before
@@ -147,7 +147,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testNoCleanupMovingActivityInSameStack() {
- final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
+ final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
.build();
mActivity.reparent(newTask, 0, null /*reason*/);
verify(mStack, times(0)).onActivityRemovedFromStack(any());
@@ -221,7 +221,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testRestartProcessIfVisible() {
doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.setSavedState(null /* savedState */);
mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
prepareFixedAspectRatioUnresizableActivity();
@@ -255,7 +255,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
// Pending options should be cleared for only ActivityRecord that was applied
- TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
activity2 = new ActivityBuilder(mService).setTask(task2).build();
activity2.updateOptionsLocked(activityOptions);
mActivity.updateOptionsLocked(activityOptions);
@@ -502,7 +502,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
mTask.setBounds(100, 100, 400, 600);
mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
ensureActivityConfiguration();
final Rect bounds = new Rect(mActivity.getBounds());
@@ -547,7 +547,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
.when(mActivity).getRequestedOrientation();
mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
ensureActivityConfiguration();
// The parent configuration doesn't change since the first resolved configuration, so the
// activity shouldn't be in the size compatibility mode.
@@ -589,7 +589,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
.setResizeMode(RESIZE_MODE_UNRESIZEABLE)
.setMaxAspectRatio(1.5f)
.build();
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
final Rect originalBounds = new Rect(mActivity.getBounds());
final int originalDpi = mActivity.getConfiguration().densityDpi;
@@ -614,7 +614,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
ensureActivityConfiguration();
final Rect originalBounds = new Rect(mActivity.getBounds());
@@ -661,7 +661,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
prepareFixedAspectRatioUnresizableActivity();
mActivity.setState(STOPPED, "testSizeCompatMode");
- mActivity.visible = false;
+ mActivity.mVisibleRequested = false;
mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
// Make the parent bounds to be different so the activity is in size compatibility mode.
setupDisplayAndParentSize(600, 1200);
@@ -829,7 +829,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// Prepare the activity record to be ready for immediate removal. It should be invisible and
// have no process. Otherwise, request to finish it will send a message to client first.
mActivity.setState(STOPPED, "test");
- mActivity.visible = false;
+ mActivity.mVisibleRequested = false;
mActivity.nowVisible = false;
// Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
// this will cause NPE when updating task's process.
@@ -838,7 +838,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// Put a visible activity on top, so the finishing activity doesn't have to wait until the
// next activity reports idle to destroy it.
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = true;
+ topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.setState(RESUMED, "test");
@@ -924,7 +924,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
mActivity.finishing = false;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.setState(RESUMED, "test");
mActivity.finishIfPossible("test", false /* oomAdj */);
@@ -940,7 +940,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
mActivity.finishing = false;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.setState(PAUSED, "test");
mActivity.finishIfPossible("test", false /* oomAdj */);
@@ -958,7 +958,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
// Put an activity on top of test activity to make it invisible and prevent us from
// accidentally resuming the topmost one again.
new ActivityBuilder(mService).build();
- mActivity.visible = false;
+ mActivity.mVisibleRequested = false;
mActivity.setState(STOPPED, "test");
mActivity.finishIfPossible("test", false /* oomAdj */);
@@ -1010,7 +1010,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_keepStateOfNextInvisible() {
final ActivityRecord currentTop = mActivity;
- currentTop.visible = currentTop.nowVisible = true;
+ currentTop.mVisibleRequested = currentTop.nowVisible = true;
// Simulates that {@code currentTop} starts an existing activity from background (so its
// state is stopped) and the starting flow just goes to place it at top.
@@ -1036,13 +1036,13 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_waitForNextVisible() {
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = true;
+ topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
topActivity.setState(PAUSED, "true");
// Mark the bottom activity as not visible, so that we will wait for it before removing
// the top one.
- mActivity.visible = false;
+ mActivity.mVisibleRequested = false;
mActivity.nowVisible = false;
mActivity.setState(STOPPED, "test");
@@ -1061,13 +1061,13 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = false;
+ topActivity.mVisibleRequested = false;
topActivity.nowVisible = false;
topActivity.finishing = true;
topActivity.setState(PAUSED, "true");
// Mark the bottom activity as not visible, so that we would wait for it before removing
// the top one.
- mActivity.visible = false;
+ mActivity.mVisibleRequested = false;
mActivity.nowVisible = false;
mActivity.setState(STOPPED, "test");
@@ -1083,12 +1083,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_waitForIdle() {
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = true;
+ topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
topActivity.setState(PAUSED, "true");
// Mark the bottom activity as already visible, so that there is no need to wait for it.
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.nowVisible = true;
mActivity.setState(RESUMED, "test");
@@ -1104,12 +1104,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_noWaitForNextVisible_stopped() {
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = false;
+ topActivity.mVisibleRequested = false;
topActivity.nowVisible = false;
topActivity.finishing = true;
topActivity.setState(STOPPED, "true");
// Mark the bottom activity as already visible, so that there is no need to wait for it.
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.nowVisible = true;
mActivity.setState(RESUMED, "test");
@@ -1125,12 +1125,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
- topActivity.visible = true;
+ topActivity.mVisibleRequested = true;
topActivity.nowVisible = true;
topActivity.finishing = true;
topActivity.setState(PAUSED, "true");
// Mark the bottom activity as already visible, so that there is no need to wait for it.
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
mActivity.nowVisible = true;
mActivity.setState(RESUMED, "test");
@@ -1139,7 +1139,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
focusedActivity.nowVisible = true;
- focusedActivity.visible = true;
+ focusedActivity.mVisibleRequested = true;
focusedActivity.setState(RESUMED, "test");
stack.mResumedActivity = focusedActivity;
@@ -1171,7 +1171,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
- for (TaskRecord t : homeStack.getAllTasks()) {
+ for (Task t : homeStack.getAllTasks()) {
homeStack.removeChild(t, "test");
}
mActivity.finishing = true;
@@ -1197,7 +1197,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
// Empty the home stack.
final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
- for (TaskRecord t : homeStack.getAllTasks()) {
+ for (Task t : homeStack.getAllTasks()) {
homeStack.removeChild(t, "test");
}
mActivity.finishing = true;
@@ -1244,12 +1244,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testDestroyImmediately_noApp_finishing() {
mActivity.app = null;
mActivity.finishing = true;
- final TaskRecord task = mActivity.getTaskRecord();
+ final Task task = mActivity.getTask();
mActivity.destroyImmediately(false /* removeFromApp */, "test");
assertEquals(DESTROYED, mActivity.getState());
- assertNull(mActivity.getTaskRecord());
+ assertNull(mActivity.getTask());
assertEquals(0, task.getChildCount());
}
@@ -1261,12 +1261,12 @@ public class ActivityRecordTests extends ActivityTestsBase {
public void testDestroyImmediately_noApp_notFinishing() {
mActivity.app = null;
mActivity.finishing = false;
- final TaskRecord task = mActivity.getTaskRecord();
+ final Task task = mActivity.getTask();
mActivity.destroyImmediately(false /* removeFromApp */, "test");
assertEquals(DESTROYED, mActivity.getState());
- assertEquals(task, mActivity.getTaskRecord());
+ assertEquals(task, mActivity.getTask());
assertEquals(1, task.getChildCount());
}
@@ -1297,13 +1297,13 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void testRemoveFromHistory() {
final ActivityStack stack = mActivity.getActivityStack();
- final TaskRecord task = mActivity.getTaskRecord();
+ final Task task = mActivity.getTask();
mActivity.removeFromHistory("test");
assertEquals(DESTROYED, mActivity.getState());
assertNull(mActivity.app);
- assertNull(mActivity.getTaskRecord());
+ assertNull(mActivity.getTask());
assertEquals(0, task.getChildCount());
assertNull(task.getStack());
assertEquals(0, stack.getChildCount());
@@ -1346,7 +1346,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
setupDisplayContentForCompatDisplayInsets();
mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
mActivity.info.maxAspectRatio = 1.5f;
- mActivity.visible = true;
+ mActivity.mVisibleRequested = true;
ensureActivityConfiguration();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 1eeca91e29d0..128ed2a9d0e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -116,7 +116,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setDisplay(newDisplay).build();
final ActivityRecord unresizableActivity = stack.getTopActivity();
- final TaskRecord task = unresizableActivity.getTaskRecord();
+ final Task task = unresizableActivity.getTask();
unresizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
task.setResizeMode(unresizableActivity.info.resizeMode);
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 57e5eb2812b4..fc44652cc668 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -43,7 +43,7 @@ import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import static com.google.common.truth.Truth.assertThat;
@@ -80,7 +80,7 @@ import org.junit.runner.RunWith;
public class ActivityStackTests extends ActivityTestsBase {
private ActivityDisplay mDefaultDisplay;
private ActivityStack mStack;
- private TaskRecord mTask;
+ private Task mTask;
@Before
public void setUp() throws Exception {
@@ -111,7 +111,7 @@ public class ActivityStackTests extends ActivityTestsBase {
final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask.reparent(destStack, true /* toTop */, TaskRecord.REPARENT_KEEP_STACK_AT_FRONT,
+ mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT,
false /* animate */, true /* deferResume*/,
"testResumedActivityFromTaskReparenting");
@@ -233,7 +233,7 @@ public class ActivityStackTests extends ActivityTestsBase {
.setStack(mStack)
.setUid(0)
.build();
- final TaskRecord task = r.getTaskRecord();
+ final Task task = r.getTask();
// Overlay must be for a different user to prevent recognizing a matching top activity
final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
.setUid(UserHandle.PER_USER_RANGE * 2).build();
@@ -256,7 +256,7 @@ public class ActivityStackTests extends ActivityTestsBase {
targetActivity);
final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
aliasActivity);
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
task.origActivity = alias;
task.realActivity = target;
new ActivityBuilder(mService).setComponent(target).setTask(task).setTargetActivity(
@@ -1006,7 +1006,7 @@ public class ActivityStackTests extends ActivityTestsBase {
// There is still an activity1 in stack1 so the activity2 should be added to finishing list
// that will be destroyed until idle.
- stack2.getTopActivity().visible = true;
+ stack2.getTopActivity().mVisibleRequested = true;
final ActivityRecord activity2 = finishTopActivity(stack2);
assertEquals(STOPPING, activity2.getState());
assertThat(mSupervisor.mStoppingActivities).contains(activity2);
@@ -1091,7 +1091,7 @@ public class ActivityStackTests extends ActivityTestsBase {
public void testResetTaskWithFinishingActivities() {
final ActivityRecord taskTop =
new ActivityBuilder(mService).setStack(mStack).setCreateTask(true).build();
- // Make all activities in the task are finishing to simulate TaskRecord#getTopActivity
+ // Make all activities in the task are finishing to simulate Task#getTopActivity
// returns null.
taskTop.finishing = true;
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 a28bbb60d70c..9af90e39da95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -132,7 +132,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
@Test
public void testUpdateLaunchBounds() {
// When in a non-resizeable stack, the task bounds should be updated.
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
+ final Task task = new TaskBuilder(mService.mStackSupervisor)
.setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.build();
@@ -143,7 +143,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
assertEquals(new Rect(), task.getStack().getRequestedOverrideBounds());
// When in a resizeable stack, the stack bounds should be updated as well.
- final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
+ final Task task2 = new TaskBuilder(mService.mStackSupervisor)
.setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.build();
@@ -712,10 +712,10 @@ public class ActivityStarterTests extends ActivityTestsBase {
verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
final ActivityRecord startedActivity = outActivity[0];
- if (startedActivity != null && startedActivity.getTaskRecord() != null) {
+ if (startedActivity != null && startedActivity.getTask() != null) {
// Remove the activity so it doesn't interfere with with subsequent activity launch
// tests from this method.
- startedActivity.getTaskRecord().removeChild(startedActivity);
+ startedActivity.getTask().removeChild(startedActivity);
}
}
@@ -807,7 +807,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
// Create another activity on top of the secondary display.
final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
+ final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
new ActivityBuilder(mService).setTask(topTask).build();
// Start activity with the same intent as {@code singleTaskActivity} on secondary display.
@@ -829,14 +829,14 @@ public class ActivityStarterTests extends ActivityTestsBase {
final ComponentName componentName = ComponentName.createRelative(
DEFAULT_COMPONENT_PACKAGE_NAME,
DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
- final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+ final Task task = new TaskBuilder(mSupervisor)
.setComponent(componentName)
.setStack(stack)
.build();
return new ActivityBuilder(mService)
.setComponent(componentName)
.setLaunchMode(LAUNCH_SINGLE_TASK)
- .setTask(taskRecord)
+ .setTask(task)
.build();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 399f28302f32..39aa51a05764 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -69,7 +69,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
removeGlobalMinSizeRestriction();
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final TaskRecord task = stack.topTask();
+ final Task task = stack.topTask();
WindowContainerTransaction t = new WindowContainerTransaction();
Rect newBounds = new Rect(10, 10, 100, 100);
t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index ce13c0bcb829..163268191df1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -117,7 +117,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
private ComponentName mComponent;
private String mTargetActivity;
- private TaskRecord mTaskRecord;
+ private Task mTask;
private String mProcessName = "name";
private int mUid = 12345;
private boolean mCreateTask;
@@ -151,8 +151,8 @@ class ActivityTestsBase extends SystemServiceTestsBase {
DEFAULT_COMPONENT_PACKAGE_NAME);
}
- ActivityBuilder setTask(TaskRecord task) {
- mTaskRecord = task;
+ ActivityBuilder setTask(Task task) {
+ mTask = task;
return this;
}
@@ -229,7 +229,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
}
if (mCreateTask) {
- mTaskRecord = new TaskBuilder(mService.mStackSupervisor)
+ mTask = new TaskBuilder(mService.mStackSupervisor)
.setComponent(mComponent)
.setStack(mStack).build();
}
@@ -265,13 +265,13 @@ class ActivityTestsBase extends SystemServiceTestsBase {
false /* rootVoiceInteraction */, mService.mStackSupervisor, options,
null /* sourceRecord */);
spyOn(activity);
- if (mTaskRecord != null) {
+ if (mTask != null) {
// fullscreen value is normally read from resources in ctor, so for testing we need
// to set it somewhere else since we can't mock resources.
doReturn(true).when(activity).occludesParent();
- mTaskRecord.addChild(activity);
+ mTask.addChild(activity);
// Make visible by default...
- activity.setHidden(false);
+ activity.setVisible(true);
}
final WindowProcessController wpc = new WindowProcessController(mService,
@@ -354,7 +354,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
return this;
}
- TaskRecord build() {
+ Task build() {
if (mStack == null && mCreateStack) {
mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -374,7 +374,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
intent.setComponent(mComponent);
intent.setFlags(mFlags);
- final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
+ final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
null /*taskDescription*/, mStack);
spyOn(task);
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 60204539d178..d415f25baab9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -62,7 +62,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
translucentOpening.setOccludesParent(false);
- translucentOpening.setHidden(true);
+ translucentOpening.setVisible(false);
mDisplayContent.mOpeningApps.add(behind);
mDisplayContent.mOpeningApps.add(translucentOpening);
assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
@@ -90,7 +90,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
translucentOpening.setOccludesParent(false);
- translucentOpening.setHidden(true);
+ translucentOpening.setVisible(false);
mDisplayContent.mOpeningApps.add(behind);
mDisplayContent.mOpeningApps.add(translucentOpening);
assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 85110745e9cb..d491569149a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -208,11 +208,9 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testSizeCompatBounds() {
- // TODO(task-merge): Move once Task is merged into TaskRecord
- final TaskRecord tr = (TaskRecord) mTask;
// Disable the real configuration resolving because we only simulate partial flow.
// TODO: Have test use full flow.
- doNothing().when(tr).computeConfigResourceOverrides(any(), any());
+ doNothing().when(mTask).computeConfigResourceOverrides(any(), any());
final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
.getBounds();
fixedBounds.set(0, 0, 1200, 1600);
@@ -254,7 +252,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
@Presubmit
public void testGetOrientation() {
- mActivity.setHidden(false);
+ mActivity.setVisible(true);
mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -263,7 +261,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation());
mActivity.setOccludesParent(true);
- mActivity.setHidden(true);
+ mActivity.setVisible(false);
mActivity.sendingToBottom = true;
// Can not specify orientation if app isn't visible even though it occludes parent.
assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation());
@@ -316,7 +314,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testSetOrientation() {
- mActivity.setHidden(false);
+ mActivity.setVisible(true);
// Assert orientation is unspecified to start.
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation());
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 ab9a7caf8b93..8db48584295a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -26,6 +26,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.Surface.ROTATION_90;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
@@ -62,6 +63,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import android.annotation.SuppressLint;
@@ -70,11 +72,14 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.metrics.LogMaker;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
import android.view.Gravity;
+import android.view.IDisplayWindowRotationCallback;
+import android.view.IDisplayWindowRotationController;
import android.view.ISystemGestureExclusionListener;
import android.view.MotionEvent;
import android.view.Surface;
@@ -389,7 +394,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
// Make sure top focused display not changed if there is a focused app.
- window1.mActivityRecord.hiddenRequested = true;
+ window1.mActivityRecord.mVisibleRequested = false;
window1.getDisplayContent().setFocusedApp(window1.mActivityRecord);
updateFocusedWindow();
assertTrue(!window1.isFocused());
@@ -656,7 +661,7 @@ public class DisplayContentTests extends WindowTestsBase {
portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
- portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
+ portraitDisplay.getDisplayRotation().setRotation(ROTATION_90);
assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
final DisplayContent landscapeDisplay = createNewDisplay();
@@ -665,7 +670,7 @@ public class DisplayContentTests extends WindowTestsBase {
landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
- landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_90);
+ landscapeDisplay.getDisplayRotation().setRotation(ROTATION_90);
assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
}
@@ -917,6 +922,45 @@ public class DisplayContentTests extends WindowTestsBase {
is(Configuration.ORIENTATION_PORTRAIT));
}
+ @Test
+ public void testRemoteRotation() {
+ DisplayContent dc = createNewDisplay();
+
+ final DisplayRotation dr = dc.getDisplayRotation();
+ Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+ Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
+ final boolean[] continued = new boolean[1];
+ spyOn(dc.mActivityDisplay);
+ Mockito.doAnswer(
+ invocation -> {
+ continued[0] = true;
+ return true;
+ }).when(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked();
+ final boolean[] called = new boolean[1];
+ mWm.mDisplayRotationController =
+ new IDisplayWindowRotationController.Stub() {
+ @Override
+ public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ IDisplayWindowRotationCallback callback) {
+ called[0] = true;
+
+ try {
+ callback.continueRotateDisplay(toRotation, null);
+ } catch (RemoteException e) {
+ assertTrue(false);
+ }
+ }
+ };
+
+ // kill any existing rotation animation (vestigial from test setup).
+ dc.setRotationAnimation(null);
+
+ mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
+ assertTrue(called[0]);
+ waitUntilHandlersIdle();
+ assertTrue(continued[0]);
+ }
+
private boolean isOptionsPanelAtRight(int displayId) {
return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 67b7a66b4794..62ab11c5a18f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -515,18 +515,16 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
final Rect outFrame = new Rect();
final Rect outContentInsets = new Rect();
final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
final DisplayCutout.ParcelableWrapper outDisplayCutout =
new DisplayCutout.ParcelableWrapper();
mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
- outOutsets, outDisplayCutout);
+ outDisplayCutout);
assertThat(outFrame, is(mFrames.mUnrestricted));
assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
- assertThat(outOutsets, is(new Rect()));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
}
@@ -540,18 +538,16 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
final Rect outFrame = new Rect();
final Rect outContentInsets = new Rect();
final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
final DisplayCutout.ParcelableWrapper outDisplayCutout =
new DisplayCutout.ParcelableWrapper();
mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
- outOutsets, outDisplayCutout);
+ outDisplayCutout);
assertThat(outFrame, is(taskBounds));
assertThat(outContentInsets, is(new Rect()));
assertThat(outStableInsets, is(new Rect()));
- assertThat(outOutsets, is(new Rect()));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
}
@@ -568,18 +564,16 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
final Rect outFrame = new Rect();
final Rect outContentInsets = new Rect();
final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
final DisplayCutout.ParcelableWrapper outDisplayCutout =
new DisplayCutout.ParcelableWrapper();
mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
true /* floatingStack */, outFrame, outContentInsets, outStableInsets,
- outOutsets, outDisplayCutout);
+ outDisplayCutout);
assertThat(outFrame, is(taskBounds));
assertThat(outContentInsets, is(new Rect()));
assertThat(outStableInsets, is(new Rect()));
- assertThat(outOutsets, is(new Rect()));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 703ebc937082..e375f8344cb4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -277,47 +277,6 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
}
@Test
- public void testDefaultToZeroOverscan() {
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-
- assertOverscan(mPrimaryDisplay, 0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
- }
-
- @Test
- public void testPersistOverscanInSameInstance() {
- final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
- try {
- mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */,
- 4 /* bottom */);
-
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
-
- assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */,
- 4 /* bottom */);
- } finally {
- mTarget.setOverscanLocked(info, 0, 0, 0, 0);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
- }
- }
-
- @Test
- public void testPersistOverscanAcrossInstances() {
- final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
- try {
- mTarget.setOverscanLocked(info, 10 /* left */, 20 /* top */, 30 /* right */,
- 40 /* bottom */);
-
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
-
- assertOverscan(mPrimaryDisplay, 10 /* left */, 20 /* top */, 30 /* right */,
- 40 /* bottom */);
- } finally {
- mTarget.setOverscanLocked(info, 0, 0, 0, 0);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
- }
- }
-
- @Test
public void testDefaultToFreeUserRotation() {
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -690,16 +649,6 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
return null;
}
- private static void assertOverscan(DisplayContent display, int left, int top, int right,
- int bottom) {
- final DisplayInfo info = display.getDisplayInfo();
-
- assertEquals(left, info.overscanLeft);
- assertEquals(top, info.overscanTop);
- assertEquals(right, info.overscanRight);
- assertEquals(bottom, info.overscanBottom);
- }
-
/**
* This method helps to ensure read and write persistent settings successfully because the
* constructor of {@link DisplayWindowSettings} should read the persistent file from the given
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 46435ebd8e15..31b658ad5043 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -89,9 +89,9 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
final ActivityOptions options = mock(ActivityOptions.class);
- mController.calculate(record.getTaskRecord(), layout, record, source, options, PHASE_BOUNDS,
+ mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
new LaunchParams());
- verify(positioner, times(1)).onCalculate(eq(record.getTaskRecord()), eq(layout), eq(record),
+ verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
eq(source), eq(options), anyInt(), any(), any());
}
@@ -114,7 +114,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
mPersister.putLaunchParams(userId, name, expected);
- mController.calculate(activity.getTaskRecord(), null /*layout*/, activity, null /*source*/,
+ mController.calculate(activity.getTask(), null /*layout*/, activity, null /*source*/,
null /*options*/, PHASE_BOUNDS, new LaunchParams());
verify(positioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
eq(expected), any());
@@ -263,9 +263,9 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
final ActivityOptions options = mock(ActivityOptions.class);
- mController.calculate(record.getTaskRecord(), layout, record, source, options, PHASE_BOUNDS,
+ mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
new LaunchParams());
- verify(positioner, times(1)).onCalculate(eq(record.getTaskRecord()), eq(layout), eq(record),
+ verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
eq(source), eq(options), eq(PHASE_BOUNDS), any(), any());
}
@@ -278,7 +278,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
final LaunchParams params = new LaunchParams();
params.mPreferredDisplayId = 2;
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -298,7 +298,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
final int windowingMode = WINDOWING_MODE_FREEFORM;
params.mWindowingMode = windowingMode;
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -323,7 +323,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
params.mWindowingMode = WINDOWING_MODE_FREEFORM;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -331,7 +331,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
mController.layoutTask(task, null /* windowLayout */);
- // TaskRecord will make adjustments to requested bounds. We only need to guarantee that the
+ // Task will make adjustments to requested bounds. We only need to guarantee that the
// reuqested bounds are expected.
assertEquals(expected, task.getRequestedOverrideBounds());
}
@@ -348,7 +348,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
params.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor).build();
mController.registerModifier(positioner);
@@ -371,7 +371,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
}
@Override
- public int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ public int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, int phase,
LaunchParams currentParams, LaunchParams outParams) {
outParams.set(mParams);
@@ -421,7 +421,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
}
@Override
- void saveTask(TaskRecord task) {
+ void saveTask(Task task) {
final int userId = task.mUserId;
final ComponentName realActivity = task.realActivity;
mTmpParams.mPreferredDisplayId = task.getStack().mDisplayId;
@@ -435,7 +435,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase {
}
@Override
- void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams params) {
+ void getLaunchParams(Task task, ActivityRecord activity, LaunchParams params) {
final int userId = task != null ? task.mUserId : activity.mUserId;
final ComponentName name = task != null
? task.realActivity : activity.mActivityComponent;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index b9fef4b008c3..0908f7193352 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -81,9 +81,9 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
private File mFolder;
private ActivityDisplay mTestDisplay;
private String mDisplayUniqueId;
- private TaskRecord mTestTask;
- private TaskRecord mTaskWithDifferentUser;
- private TaskRecord mTaskWithDifferentComponent;
+ private Task mTestTask;
+ private Task mTaskWithDifferentUser;
+ private Task mTaskWithDifferentComponent;
private PackageManagerInternal mMockPmi;
private PackageManagerInternal.PackageListObserver mObserver;
@@ -234,7 +234,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
ACTIVITY_TYPE_STANDARD, /* onTop */ true);
- final TaskRecord anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
+ final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT)
.setUserId(TEST_USER_ID)
.setStack(stack)
@@ -246,7 +246,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
ACTIVITY_TYPE_STANDARD, /* onTop */ true);
- final TaskRecord anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
+ final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
.setComponent(TEST_COMPONENT)
.setUserId(ALTERNATIVE_USER_ID)
.setStack(stack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 05e173c957d3..6ced8160b426 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -165,7 +165,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_once() throws Exception {
// GIVEN a task record with whitelisted auth
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -182,8 +182,8 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_twice() throws Exception {
// GIVEN two task records with whitelisted auth
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
- TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -202,7 +202,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_pinningRequest() {
// GIVEN a task record that is not whitelisted, i.e. with pinned auth
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -214,7 +214,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_pinnedBySystem() throws Exception {
// GIVEN a task record with pinned auth
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
// WHEN the system calls startLockTaskMode
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
@@ -233,41 +233,41 @@ public class LockTaskControllerTest {
@Test
public void testLockTaskViolation() {
// GIVEN one task record with whitelisted auth that is in lock task mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
// THEN it's a lock task violation to launch another task that is not whitelisted
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
- TaskRecord.LOCK_TASK_AUTH_PINNABLE)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
+ Task.LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
- TaskRecord.LOCK_TASK_AUTH_DONT_LOCK)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
+ Task.LOCK_TASK_AUTH_DONT_LOCK)));
// THEN it's no a lock task violation to launch another task that is whitelisted
- assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
- TaskRecord.LOCK_TASK_AUTH_WHITELISTED)));
- assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
- TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE)));
+ assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+ Task.LOCK_TASK_AUTH_WHITELISTED)));
+ assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+ Task.LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
- assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
- TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
+ assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+ Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
}
@Test
public void testLockTaskViolation_emergencyCall() {
// GIVEN one task record with whitelisted auth that is in lock task mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
- TaskRecord keypad = getTaskRecord(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
- TaskRecord.LOCK_TASK_AUTH_PINNABLE);
- TaskRecord callAction = getTaskRecord(new Intent(Intent.ACTION_CALL_EMERGENCY),
- TaskRecord.LOCK_TASK_AUTH_PINNABLE);
- TaskRecord dialer = getTaskRecord("com.example.dialer", TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ Task keypad = getTask(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
+ Task.LOCK_TASK_AUTH_PINNABLE);
+ Task callAction = getTask(new Intent(Intent.ACTION_CALL_EMERGENCY),
+ Task.LOCK_TASK_AUTH_PINNABLE);
+ Task dialer = getTask("com.example.dialer", Task.LOCK_TASK_AUTH_PINNABLE);
when(mTelecomManager.getSystemDialerPackage())
.thenReturn(dialer.intent.getComponent().getPackageName());
@@ -291,7 +291,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode() throws Exception {
// GIVEN one task record with whitelisted auth that is in lock task mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -308,7 +308,7 @@ public class LockTaskControllerTest {
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
// GIVEN one task record with whitelisted auth that is in lock task mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -320,7 +320,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_systemCaller() {
// GIVEN one task record with whitelisted auth that is in lock task mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -333,8 +333,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
// GIVEN two task records with whitelisted auth that is in lock task mode
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
- TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -354,8 +354,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
// GIVEN two task records with whitelisted auth that is in lock task mode
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
- TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -375,7 +375,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_pinned() throws Exception {
// GIVEN one task records that is in pinned mode
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
// GIVEN that the keyguard is required to show after unlocking
Settings.Secure.putInt(mContext.getContentResolver(),
@@ -402,8 +402,8 @@ public class LockTaskControllerTest {
@Test
public void testClearLockedTasks() throws Exception {
// GIVEN two task records with whitelisted auth that is in lock task mode
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
- TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -430,7 +430,7 @@ public class LockTaskControllerTest {
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -450,7 +450,7 @@ public class LockTaskControllerTest {
.thenReturn(true);
// AND there is a task record
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -467,7 +467,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -484,7 +484,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -531,8 +531,8 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
// GIVEN two tasks which are whitelisted initially
- TaskRecord tr1 = getTaskRecordForUpdate(TEST_PACKAGE_NAME, true);
- TaskRecord tr2 = getTaskRecordForUpdate(TEST_PACKAGE_NAME_2, false);
+ Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
+ Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
@@ -570,7 +570,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -612,7 +612,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -634,7 +634,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -693,18 +693,18 @@ public class LockTaskControllerTest {
assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0);
}
- private TaskRecord getTaskRecord(int lockTaskAuth) {
- return getTaskRecord(TEST_PACKAGE_NAME, lockTaskAuth);
+ private Task getTask(int lockTaskAuth) {
+ return getTask(TEST_PACKAGE_NAME, lockTaskAuth);
}
- private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) {
+ private Task getTask(String pkg, int lockTaskAuth) {
final Intent intent = new Intent()
.setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME));
- return getTaskRecord(intent, lockTaskAuth);
+ return getTask(intent, lockTaskAuth);
}
- private TaskRecord getTaskRecord(Intent intent, int lockTaskAuth) {
- TaskRecord tr = mock(TaskRecord.class);
+ private Task getTask(Intent intent, int lockTaskAuth) {
+ Task tr = mock(Task.class);
tr.mLockTaskAuth = lockTaskAuth;
tr.intent = intent;
tr.mUserId = TEST_USER_ID;
@@ -714,17 +714,15 @@ public class LockTaskControllerTest {
/**
* @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
*/
- private TaskRecord getTaskRecordForUpdate(String pkg, boolean isAppAware) {
+ private Task getTaskForUpdate(String pkg, boolean isAppAware) {
final int authIfWhitelisted = isAppAware
- ? TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE
- : TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
- TaskRecord tr = getTaskRecord(pkg, authIfWhitelisted);
+ ? Task.LOCK_TASK_AUTH_LAUNCHABLE
+ : Task.LOCK_TASK_AUTH_WHITELISTED;
+ Task tr = getTask(pkg, authIfWhitelisted);
doAnswer((invocation) -> {
boolean isWhitelisted =
mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isWhitelisted
- ? authIfWhitelisted
- : TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+ tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index cc99fe0fd1c3..e0ffb0d03f89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -101,8 +101,8 @@ public class RecentTasksTest extends ActivityTestsBase {
private TestRecentTasks mRecentTasks;
private TestRunningTasks mRunningTasks;
- private ArrayList<TaskRecord> mTasks;
- private ArrayList<TaskRecord> mSameDocumentTasks;
+ private ArrayList<Task> mTasks;
+ private ArrayList<Task> mSameDocumentTasks;
private CallbacksRecorder mCallbacksRecorder;
@@ -172,8 +172,8 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTasksNoMultiple_expectNoTrim() {
// Add same non-multiple-task document tasks will remove the task (to re-add it) but not
// trim it
- TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
- TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
+ Task documentTask1 = createDocumentTask(".DocumentTask1");
+ Task documentTask2 = createDocumentTask(".DocumentTask1");
mRecentTasks.add(documentTask1);
mRecentTasks.add(documentTask2);
assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
@@ -186,8 +186,8 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTasksMaxTaskRecents_expectNoTrim() {
// Add a task hitting max-recents for that app will remove the task (to add the next one)
// but not trim it
- TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
- TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
+ Task documentTask1 = createDocumentTask(".DocumentTask1");
+ Task documentTask2 = createDocumentTask(".DocumentTask1");
documentTask1.maxRecents = 1;
documentTask2.maxRecents = 1;
mRecentTasks.add(documentTask1);
@@ -202,7 +202,7 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTasksSameTask_expectNoTrim() {
// Add a task that is already in the task list does not trigger any callbacks, it just
// moves in the list
- TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
+ Task documentTask1 = createDocumentTask(".DocumentTask1");
mRecentTasks.add(documentTask1);
mRecentTasks.add(documentTask1);
assertThat(mCallbacksRecorder.mAdded).hasSize(1);
@@ -214,9 +214,9 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testAddTasksMultipleDocumentTasks_expectNoTrim() {
// Add same multiple-task document tasks does not trim the first tasks
- TaskRecord documentTask1 = createDocumentTask(".DocumentTask1",
+ Task documentTask1 = createDocumentTask(".DocumentTask1",
FLAG_ACTIVITY_MULTIPLE_TASK);
- TaskRecord documentTask2 = createDocumentTask(".DocumentTask1",
+ Task documentTask2 = createDocumentTask(".DocumentTask1",
FLAG_ACTIVITY_MULTIPLE_TASK);
mRecentTasks.add(documentTask1);
mRecentTasks.add(documentTask2);
@@ -231,10 +231,10 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTasksMultipleTasks_expectRemovedNoTrim() {
// Add multiple same-affinity non-document tasks, ensure that it removes the other task,
// but that it does not trim it
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.build();
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.build();
mRecentTasks.add(task1);
@@ -255,10 +255,10 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTasksDifferentStacks_expectNoRemove() {
// Adding the same task with different activity types should not trigger removal of the
// other task
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.setStack(mDisplay.getHomeStack()).build();
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.setStack(mStack).build();
mRecentTasks.add(task1);
@@ -274,7 +274,7 @@ public class RecentTasksTest extends ActivityTestsBase {
public void testAddTaskCompatibleActivityType_expectRemove() {
// Test with undefined activity type since the type is not persisted by the task persister
// and we want to ensure that a new task will match a restored task
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -283,7 +283,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.add(task1);
mCallbacksRecorder.clear();
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -298,7 +298,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() {
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.setUserId(TEST_USER_0_ID)
@@ -308,7 +308,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.add(task1);
mCallbacksRecorder.clear();
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.setUserId(TEST_USER_1_ID)
@@ -323,7 +323,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testAddTaskCompatibleWindowingMode_expectRemove() {
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -332,7 +332,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.add(task1);
mCallbacksRecorder.clear();
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -349,7 +349,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testAddTaskIncompatibleWindowingMode_expectNoRemove() {
- TaskRecord task1 = createTaskBuilder(".Task1")
+ Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -357,7 +357,7 @@ public class RecentTasksTest extends ActivityTestsBase {
assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode());
mRecentTasks.add(task1);
- TaskRecord task2 = createTaskBuilder(".Task1")
+ Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setStack(mStack)
.build();
@@ -421,13 +421,13 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testOrderedIteration() {
mRecentTasks.setOnlyTestVisibleRange();
- TaskRecord task1 = createTaskBuilder(".Task1").build();
+ Task task1 = createTaskBuilder(".Task1").build();
task1.lastActiveTime = new Random().nextInt();
- TaskRecord task2 = createTaskBuilder(".Task1").build();
+ Task task2 = createTaskBuilder(".Task1").build();
task2.lastActiveTime = new Random().nextInt();
- TaskRecord task3 = createTaskBuilder(".Task1").build();
+ Task task3 = createTaskBuilder(".Task1").build();
task3.lastActiveTime = new Random().nextInt();
- TaskRecord task4 = createTaskBuilder(".Task1").build();
+ Task task4 = createTaskBuilder(".Task1").build();
task4.lastActiveTime = new Random().nextInt();
mRecentTasks.add(task1);
mRecentTasks.add(task2);
@@ -435,9 +435,9 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.add(task4);
long prevLastActiveTime = 0;
- final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+ final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
for (int i = 0; i < tasks.size(); i++) {
- final TaskRecord task = tasks.get(i);
+ final Task task = tasks.get(i);
assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime);
prevLastActiveTime = task.lastActiveTime;
}
@@ -462,8 +462,8 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testTrimQuietProfileTasks() {
mRecentTasks.setOnlyTestVisibleRange();
- TaskRecord qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
- TaskRecord qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
+ Task qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
+ Task qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
mRecentTasks.add(qt1);
mRecentTasks.add(qt2);
@@ -479,14 +479,14 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
- TaskRecord t1 = createTaskBuilder(".Task1").build();
+ Task t1 = createTaskBuilder(".Task1").build();
t1.touchActiveTime();
mRecentTasks.add(t1);
// Force a small sleep just beyond the session duration
SystemClock.sleep(75);
- TaskRecord t2 = createTaskBuilder(".Task2").build();
+ Task t2 = createTaskBuilder(".Task2").build();
t2.touchActiveTime();
mRecentTasks.add(t2);
@@ -499,10 +499,10 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
- TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
.setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
.build();
- TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+ Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
.setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
.build();
@@ -519,12 +519,12 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
// Create some set of tasks, some of which are visible and some are not
- TaskRecord homeTask = setTaskActivityType(
+ Task homeTask = setTaskActivityType(
createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
ACTIVITY_TYPE_HOME);
homeTask.mUserSetupComplete = true;
mRecentTasks.add(homeTask);
- TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
.setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
.build();
excludedTask1.mUserSetupComplete = true;
@@ -537,25 +537,25 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testVisibleTasks_excludedFromRecents_withExcluded() {
// Create some set of tasks, some of which are visible and some are not
- TaskRecord t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
+ Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
t1.mUserSetupComplete = true;
mRecentTasks.add(t1);
- TaskRecord homeTask = setTaskActivityType(
+ Task homeTask = setTaskActivityType(
createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
ACTIVITY_TYPE_HOME);
homeTask.mUserSetupComplete = true;
mRecentTasks.add(homeTask);
- TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
.setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
.build();
excludedTask1.mUserSetupComplete = true;
mRecentTasks.add(excludedTask1);
- TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+ Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
.setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
.build();
excludedTask2.mUserSetupComplete = true;
mRecentTasks.add(excludedTask2);
- TaskRecord t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
+ Task t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
t2.mUserSetupComplete = true;
mRecentTasks.add(t2);
@@ -568,7 +568,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
for (int i = 0; i < 4; i++) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
task.touchActiveTime();
mRecentTasks.add(task);
}
@@ -589,7 +589,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
for (int i = 0; i < 5; i++) {
- final TaskRecord task = mTasks.get(i);
+ final Task task = mTasks.get(i);
task.touchActiveTime();
mRecentTasks.add(task);
}
@@ -612,7 +612,7 @@ public class RecentTasksTest extends ActivityTestsBase {
ActivityStack singleTaskStack = singleTaskDisplay.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
.setStack(singleTaskStack)
.build();
@@ -771,7 +771,7 @@ public class RecentTasksTest extends ActivityTestsBase {
// Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
// the home stack is trimmed once a new task is added
- final TaskRecord behindHomeTask = createTaskBuilder(".Task1")
+ final Task behindHomeTask = createTaskBuilder(".Task1")
.setStack(behindHomeStack)
.build();
mRecentTasks.add(behindHomeTask);
@@ -809,7 +809,7 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task4").build());
mRecentTasks.removeTasksByPackageName("com.android.pkg1", TEST_USER_0_ID);
- final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+ final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
for (int i = 0; i < tasks.size(); i++) {
if (tasks.get(i).intent.getComponent().getPackageName().equals("com.android.pkg1")) {
fail("Expected com.android.pkg1 tasks to be removed");
@@ -822,30 +822,30 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
// Create some set of tasks, some of which are visible and some are not
- TaskRecord t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
+ Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
mRecentTasks.add(t1);
mRecentTasks.add(setTaskActivityType(
createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
ACTIVITY_TYPE_HOME));
- TaskRecord t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
+ Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
mRecentTasks.add(t2);
mRecentTasks.add(setTaskWindowingMode(
createTaskBuilder("com.android.pkg1", ".PipTask").build(),
WINDOWING_MODE_PINNED));
- TaskRecord t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
+ Task t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
mRecentTasks.add(t3);
// Create some more tasks that are out of visible range, but are still visible
- TaskRecord t4 = createTaskBuilder("com.android.pkg3", ".Task4").build();
+ Task t4 = createTaskBuilder("com.android.pkg3", ".Task4").build();
mRecentTasks.add(t4);
- TaskRecord t5 = createTaskBuilder("com.android.pkg3", ".Task5").build();
+ Task t5 = createTaskBuilder("com.android.pkg3", ".Task5").build();
mRecentTasks.add(t5);
// Create some more tasks that are out of the active session range, but are still visible
- TaskRecord t6 = createTaskBuilder("com.android.pkg3", ".Task6").build();
+ Task t6 = createTaskBuilder("com.android.pkg3", ".Task6").build();
t6.lastActiveTime = SystemClock.elapsedRealtime() - 200;
mRecentTasks.add(t6);
- TaskRecord t7 = createTaskBuilder("com.android.pkg3", ".Task7").build();
+ Task t7 = createTaskBuilder("com.android.pkg3", ".Task7").build();
t7.lastActiveTime = SystemClock.elapsedRealtime() - 200;
mRecentTasks.add(t7);
@@ -859,17 +859,17 @@ public class RecentTasksTest extends ActivityTestsBase {
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
// Create a visible task per user
- TaskRecord t1 = createTaskBuilder(".Task1")
+ Task t1 = createTaskBuilder(".Task1")
.setUserId(TEST_USER_0_ID)
.build();
mRecentTasks.add(t1);
- TaskRecord t2 = createTaskBuilder(".Task2")
+ Task t2 = createTaskBuilder(".Task2")
.setUserId(TEST_QUIET_USER_ID)
.build();
mRecentTasks.add(t2);
- TaskRecord t3 = createTaskBuilder(".Task3")
+ Task t3 = createTaskBuilder(".Task3")
.setUserId(TEST_USER_1_ID)
.build();
mRecentTasks.add(t3);
@@ -881,7 +881,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void testNotRestoreRecentTaskApis() {
- final TaskRecord task = createTaskBuilder(".Task").build();
+ final Task task = createTaskBuilder(".Task").build();
final int taskId = task.mTaskId;
mRecentTasks.add(task);
// Only keep the task in RecentTasks.
@@ -906,7 +906,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void addTask_callsTaskNotificationController() {
- final TaskRecord task = createTaskBuilder(".Task").build();
+ final Task task = createTaskBuilder(".Task").build();
mRecentTasks.add(task);
mRecentTasks.remove(task);
@@ -918,7 +918,7 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void removeTask_callsTaskNotificationController() {
- final TaskRecord task = createTaskBuilder(".Task").build();
+ final Task task = createTaskBuilder(".Task").build();
mRecentTasks.add(task);
mRecentTasks.remove(task);
@@ -931,8 +931,8 @@ public class RecentTasksTest extends ActivityTestsBase {
@Test
public void removeALlVisibleTask_callsTaskNotificationController_twice() {
- final TaskRecord task1 = createTaskBuilder(".Task").build();
- final TaskRecord task2 = createTaskBuilder(".Task2").build();
+ final Task task1 = createTaskBuilder(".Task").build();
+ final Task task2 = createTaskBuilder(".Task2").build();
mRecentTasks.add(task1);
mRecentTasks.add(task2);
@@ -948,8 +948,8 @@ public class RecentTasksTest extends ActivityTestsBase {
* Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
*/
- private void assertRecentTasksOrder(TaskRecord... expectedTasks) {
- ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+ private void assertRecentTasksOrder(Task... expectedTasks) {
+ ArrayList<Task> tasks = mRecentTasks.getRawTasks();
assertTrue(expectedTasks.length == tasks.size());
for (int i = 0; i < tasks.size(); i++) {
assertTrue(expectedTasks[i] == tasks.get(i));
@@ -960,7 +960,7 @@ public class RecentTasksTest extends ActivityTestsBase {
* Ensures that the recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
*/
- private void assertGetRecentTasksOrder(int getRecentTaskFlags, TaskRecord... expectedTasks) {
+ private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) {
doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
@@ -1079,12 +1079,12 @@ public class RecentTasksTest extends ActivityTestsBase {
.setUserId(TEST_USER_0_ID);
}
- private TaskRecord createDocumentTask(String className) {
+ private Task createDocumentTask(String className) {
return createDocumentTask(className, 0);
}
- private TaskRecord createDocumentTask(String className, int flags) {
- TaskRecord task = createTaskBuilder(className)
+ private Task createDocumentTask(String className, int flags) {
+ Task task = createTaskBuilder(className)
.setFlags(FLAG_ACTIVITY_NEW_DOCUMENT | flags)
.build();
task.affinity = null;
@@ -1092,7 +1092,7 @@ public class RecentTasksTest extends ActivityTestsBase {
return task;
}
- private TaskRecord setTaskActivityType(TaskRecord task,
+ private Task setTaskActivityType(Task task,
@WindowConfiguration.ActivityType int activityType) {
Configuration config1 = new Configuration();
config1.windowConfiguration.setActivityType(activityType);
@@ -1100,7 +1100,7 @@ public class RecentTasksTest extends ActivityTestsBase {
return task;
}
- private TaskRecord setTaskWindowingMode(TaskRecord task,
+ private Task setTaskWindowingMode(Task task,
@WindowConfiguration.WindowingMode int windowingMode) {
Configuration config1 = new Configuration();
config1.windowConfiguration.setWindowingMode(windowingMode);
@@ -1112,14 +1112,14 @@ public class RecentTasksTest extends ActivityTestsBase {
assertTrimmed();
}
- private void assertTrimmed(TaskRecord... tasks) {
- final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.mTrimmed;
- final ArrayList<TaskRecord> removed = mCallbacksRecorder.mRemoved;
+ private void assertTrimmed(Task... tasks) {
+ final ArrayList<Task> trimmed = mCallbacksRecorder.mTrimmed;
+ final ArrayList<Task> removed = mCallbacksRecorder.mRemoved;
assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size())
.that(trimmed).hasSize(tasks.length);
assertWithMessage("Expected " + tasks.length + " removed tasks, got " + removed.size())
.that(removed).hasSize(tasks.length);
- for (TaskRecord task : tasks) {
+ for (Task task : tasks) {
assertWithMessage("Expected trimmed task: " + task).that(trimmed).contains(task);
assertWithMessage("Expected removed task: " + task).that(removed).contains(task);
}
@@ -1141,9 +1141,9 @@ public class RecentTasksTest extends ActivityTestsBase {
}
private static class CallbacksRecorder implements Callbacks {
- public final ArrayList<TaskRecord> mAdded = new ArrayList<>();
- public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>();
- public final ArrayList<TaskRecord> mRemoved = new ArrayList<>();
+ public final ArrayList<Task> mAdded = new ArrayList<>();
+ public final ArrayList<Task> mTrimmed = new ArrayList<>();
+ public final ArrayList<Task> mRemoved = new ArrayList<>();
void clear() {
mAdded.clear();
@@ -1152,12 +1152,12 @@ public class RecentTasksTest extends ActivityTestsBase {
}
@Override
- public void onRecentTaskAdded(TaskRecord task) {
+ public void onRecentTaskAdded(Task task) {
mAdded.add(task);
}
@Override
- public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+ public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
if (wasTrimmed) {
mTrimmed.add(task);
}
@@ -1167,7 +1167,7 @@ public class RecentTasksTest extends ActivityTestsBase {
private static class TestTaskPersister extends TaskPersister {
public SparseBooleanArray mUserTaskIdsOverride;
- public ArrayList<TaskRecord> mUserTasksOverride;
+ public ArrayList<Task> mUserTasksOverride;
TestTaskPersister(File workingDir) {
super(workingDir);
@@ -1182,7 +1182,7 @@ public class RecentTasksTest extends ActivityTestsBase {
}
@Override
- List<TaskRecord> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
+ List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
if (mUserTasksOverride != null) {
return mUserTasksOverride;
}
@@ -1270,7 +1270,7 @@ public class RecentTasksTest extends ActivityTestsBase {
}
@Override
- protected boolean isTrimmable(TaskRecord task) {
+ protected boolean isTrimmable(Task task) {
return mIsTrimmableOverride || super.isTrimmable(task);
}
}
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 702600402d8e..1abd3662165e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -149,7 +149,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord hiddenActivity = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- hiddenActivity.setHidden(true);
+ hiddenActivity.setVisible(false);
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
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 75f50ec54886..06d96fee3757 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -106,12 +106,12 @@ public class RecentsAnimationTest extends ActivityTestsBase {
RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
mRecentsComponent, true /* getRecentsAnimation */);
// The launch-behind state should make the recents activity visible.
- assertTrue(recentActivity.visible);
+ assertTrue(recentActivity.mVisibleRequested);
// Simulate the animation is cancelled without changing the stack order.
recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */);
// The non-top recents activity should be invisible by the restored launch-behind state.
- assertFalse(recentActivity.visible);
+ assertFalse(recentActivity.mVisibleRequested);
}
@Test
@@ -158,7 +158,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// The activity is started in background so it should be invisible and will be stopped.
assertThat(recentsActivity).isNotNull();
assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
- assertFalse(recentsActivity.visible);
+ assertFalse(recentsActivity.mVisibleRequested);
// Assume it is stopped to test next use case.
recentsActivity.activityStoppedLocked(null /* newIcicle */, null /* newPersistentState */,
@@ -234,7 +234,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// Start the recents animation.
RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
- targetActivity.getTaskRecord().getBaseIntent().getComponent(),
+ targetActivity.getTask().getBaseIntent().getComponent(),
true /* getRecentsAnimation */);
// Ensure launch-behind is set for being visible.
assertTrue(targetActivity.mLaunchTaskBehind);
@@ -342,7 +342,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
.setCreateTask(true)
.setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
.build();
- otherUserHomeActivity.getTaskRecord().mUserId = TEST_USER_ID;
+ otherUserHomeActivity.getTask().mUserId = TEST_USER_ID;
ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -357,11 +357,11 @@ public class RecentsAnimationTest extends ActivityTestsBase {
any() /* starting */, anyInt() /* configChanges */,
anyBoolean() /* preserveWindows */);
- startRecentsActivity(otherUserHomeActivity.getTaskRecord().getBaseIntent().getComponent(),
+ startRecentsActivity(otherUserHomeActivity.getTask().getBaseIntent().getComponent(),
true);
// Ensure we find the task for the right user and it is made visible
- assertTrue(otherUserHomeActivity.visible);
+ assertTrue(otherUserHomeActivity.mVisibleRequested);
}
private void startRecentsActivity() {
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 33ddbbbcf039..3cc781c2c2b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -101,7 +101,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testRestoringInvalidTask() {
mRootActivityContainer.getDefaultDisplay().removeAllTasks();
- TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
+ Task task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
assertNull(task);
}
@@ -114,7 +114,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
public void testReplacingTaskInPinnedStack() {
final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(mFullscreenStack).build();
- final TaskRecord task = firstActivity.getTaskRecord();
+ final Task task = firstActivity.getTask();
final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
.setStack(mFullscreenStack).build();
@@ -148,7 +148,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
}
private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) {
- final TaskRecord task = stack.getAllTasks().get(0);
+ final Task task = stack.getAllTasks().get(0);
final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
for (int i = 0; i < task.getChildCount(); i++) {
@@ -279,7 +279,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
assertTrue(pinnedActivity.isFocusable());
// Without the overridding activity, stack should not be focusable.
- pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability");
+ pinnedStack.removeChild(pinnedActivity.getTask(), "testFocusability");
assertFalse(pinnedStack.isFocusable());
}
@@ -294,7 +294,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay()
.createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
// Find a launch stack for the top activity in split-screen primary, while requesting
@@ -323,7 +323,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
.setOnTop(true)
.build();
- final TaskRecord task = primaryStack.topTask();
+ final Task task = primaryStack.topTask();
// Resize dock stack.
mService.resizeDockedStack(stackSize, taskSize, null, null, null);
@@ -343,7 +343,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
.setOnTop(false)
.build();
- final TaskRecord targetTask = targetStack.getChildAt(0);
+ final Task targetTask = targetStack.getChildAt(0);
// Create Recents on top of the display.
final ActivityStack stack = new StackBuilder(mRootActivityContainer).setActivityType(
@@ -366,14 +366,14 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
// Create Recents on secondary display.
final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
ActivityDisplay.POSITION_TOP);
final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
new ActivityBuilder(mService).setTask(task).build();
final String reason = "findTaskToMoveToFront";
@@ -393,7 +393,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
display.positionChildAtBottom(targetStack);
@@ -449,7 +449,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
ActivityDisplay.POSITION_TOP);
final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
new ActivityBuilder(mService).setTask(task).build();
doReturn(true).when(mRootActivityContainer).resumeHomeActivity(any(), any(), anyInt());
@@ -473,7 +473,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
@@ -493,7 +493,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
display.positionChildAtBottom(targetStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index af6649d8d61d..15dcbf5468c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -20,8 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -105,9 +103,9 @@ public class RunningTasksTest extends ActivityTestsBase {
/**
* Create a task with a single activity in it, with the given last active time.
*/
- private TaskRecord createTask(ActivityStack stack, String className, int taskId,
+ private Task createTask(ActivityStack stack, String className, int taskId,
int lastActiveTime) {
- final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
+ final Task task = new TaskBuilder(mService.mStackSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
.setStack(stack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 5a141ae983f2..27ebd5ad94aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -95,7 +95,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
@Test
public void testReturnsSkipWithEmptyActivity() {
- final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ final Task task = new TaskBuilder(mSupervisor).build();
assertEquals(RESULT_SKIP, mTarget.onCalculate(task, /* layout */ null,
/* activity */ null, /* source */ null, /* options */ null, mCurrent, mResult));
}
@@ -183,7 +183,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
ActivityRecord source = createSourceActivity(freeformDisplay);
- assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTask(),
/* layout */ null, mActivity, source, /* options */ null, mCurrent, mResult));
assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -195,7 +195,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
WINDOWING_MODE_FREEFORM);
ActivityRecord source = createSourceActivity(freeformDisplay);
- assertEquals(RESULT_CONTINUE, mTarget.onCalculate(source.getTaskRecord(), null /* layout */,
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(source.getTask(), null /* layout */,
null /* activity */, null /* source */, null /* options */, mCurrent, mResult));
assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -214,7 +214,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
source.mHandoverLaunchDisplayId = freeformDisplay.mDisplayId;
source.noDisplay = true;
- assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTask(),
null /* layout */, mActivity, source, null /* options */, mCurrent, mResult));
assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -1319,7 +1319,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityStack stack = display.createStack(display.getWindowingMode(),
ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
// Just work around the unnecessary adjustments for bounds.
task.getWindowConfiguration().setBounds(bounds);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index d2342f081fa1..8e32dad4c758 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -66,8 +66,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase {
any(InputChannel.class))).thenReturn(true);
mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
- // TODO(task-merge): Remove cast.
- ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE);
+ mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
mWindow.mInputChannel = new InputChannel();
mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
@@ -143,8 +142,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase {
doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
- // TODO(task-merge): Remove cast.
- ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE);
+ mWindow.getTask().setResizeMode(RESIZE_MODE_UNRESIZEABLE);
mTarget.handleTapOutsideTask(content, 0, 0);
// Wait until the looper processes finishTaskPositioning.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 2cafc965e648..faa9f11f97bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -72,13 +72,12 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.app.IVoiceInteractor;
-import com.android.server.wm.TaskRecord.TaskRecordFactory;
+import com.android.server.wm.Task.TaskFactory;
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mockito;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -88,10 +87,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.util.ArrayList;
/**
- * Tests for exercising {@link TaskRecord}.
+ * Tests for exercising {@link Task}.
*
* Build/Install/Run:
* atest WmTests:TaskRecordTests
@@ -107,31 +105,31 @@ public class TaskRecordTests extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
- TaskRecord.setTaskRecordFactory(null);
+ Task.setTaskFactory(null);
mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
removeGlobalMinSizeRestriction();
}
@Test
public void testRestoreWindowedTask() throws Exception {
- final TaskRecord expected = createTaskRecord(64);
+ final Task expected = createTask(64);
expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
final byte[] serializedBytes = serializeToBytes(expected);
- final TaskRecord actual = restoreFromBytes(serializedBytes);
+ final Task actual = restoreFromBytes(serializedBytes);
assertEquals(expected.mTaskId, actual.mTaskId);
assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
}
@Test
public void testDefaultTaskFactoryNotNull() throws Exception {
- assertNotNull(TaskRecord.getTaskRecordFactory());
+ assertNotNull(Task.getTaskFactory());
}
/** Ensure we have no chance to modify the original intent. */
@Test
public void testCopyBaseIntentForTaskInfo() {
- final TaskRecord task = createTaskRecord(1);
+ final Task task = createTask(1);
task.setTaskDescription(new ActivityManager.TaskDescription());
final TaskInfo info = task.getTaskInfo();
@@ -141,19 +139,19 @@ public class TaskRecordTests extends ActivityTestsBase {
@Test
public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
- TestTaskRecordFactory factory = new TestTaskRecordFactory();
- TaskRecord.setTaskRecordFactory(factory);
+ TestTaskFactory factory = new TestTaskFactory();
+ Task.setTaskFactory(factory);
assertFalse(factory.mCreated);
- TaskRecord.create(null, 0, null, null, null, null);
+ Task.create(null, 0, null, null, null, null);
assertTrue(factory.mCreated);
}
@Test
public void testReturnsToHomeStack() throws Exception {
- final TaskRecord task = createTaskRecord(1);
+ final Task task = createTask(1);
assertFalse(task.returnsToHomeStack());
task.intent = null;
assertFalse(task.returnsToHomeStack());
@@ -198,7 +196,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
final Configuration parentConfig = stack.getConfiguration();
parentConfig.windowConfiguration.setBounds(parentBounds);
parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
@@ -237,7 +235,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- TaskRecord task = stack.getChildAt(0);
+ Task task = stack.getChildAt(0);
task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
@@ -281,7 +279,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- TaskRecord task = stack.getChildAt(0);
+ Task task = stack.getChildAt(0);
ActivityRecord root = task.getTopActivity();
assertEquals(fullScreenBounds, task.getBounds());
@@ -345,7 +343,7 @@ public class TaskRecordTests extends ActivityTestsBase {
display.getRequestedOverrideConfiguration());
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- TaskRecord task = stack.getChildAt(0);
+ Task task = stack.getChildAt(0);
ActivityRecord root = task.getTopActivity();
final WindowContainer parentWindowContainer =
@@ -355,7 +353,7 @@ public class TaskRecordTests extends ActivityTestsBase {
doReturn(parentWindowContainer).when(task).getParent();
doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
- // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
+ // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
// bounds because its parent says it will handle it at a later time.
root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(root, task.getRootActivity());
@@ -365,7 +363,7 @@ public class TaskRecordTests extends ActivityTestsBase {
@Test
public void testComputeConfigResourceOverrides() {
- final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ final Task task = new TaskBuilder(mSupervisor).build();
final Configuration inOutConfig = new Configuration();
final Configuration parentConfig = new Configuration();
final int longSide = 1200;
@@ -434,7 +432,7 @@ public class TaskRecordTests extends ActivityTestsBase {
info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
info.targetActivity = targetClassName;
- final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
+ final Task task = Task.create(mService, 1 /* taskId */, info, intent,
null /* taskDescription */, null /*stack*/);
assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
task.intent.getComponent().getClassName());
@@ -457,7 +455,7 @@ public class TaskRecordTests extends ActivityTestsBase {
/** Test that root activity index is reported correctly for several activities in the task. */
@Test
public void testFindRootIndex() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
@@ -471,7 +469,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testFindRootIndex_finishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add extra two activities and mark the two on the bottom as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -489,7 +487,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testFindRootIndex_effectiveRoot() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
@@ -503,7 +501,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
// one above as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
@@ -522,7 +520,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Set relinquishTaskIdentity for the only activity in the task
task.getChildAt(0).info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -536,7 +534,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Set relinquishTaskIdentity for all activities in the task
final ActivityRecord activity0 = task.getChildAt(0);
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -547,10 +545,10 @@ public class TaskRecordTests extends ActivityTestsBase {
task.getChildCount() - 1, task.findRootIndex(true /* effectiveRoot*/));
}
- /** Test that bottom-most activity is reported in {@link TaskRecord#getRootActivity()}. */
+ /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
@Test
public void testGetRootActivity() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
@@ -559,11 +557,11 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test that first non-finishing activity is reported in {@link TaskRecord#getRootActivity()}.
+ * Test that first non-finishing activity is reported in {@link Task#getRootActivity()}.
*/
@Test
public void testGetRootActivity_finishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
// Mark the root as finishing
@@ -574,11 +572,11 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test that relinquishTaskIdentity flag is ignored in {@link TaskRecord#getRootActivity()}.
+ * Test that relinquishTaskIdentity flag is ignored in {@link Task#getRootActivity()}.
*/
@Test
public void testGetRootActivity_relinquishTaskIdentity() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -590,12 +588,12 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test that no activity is reported in {@link TaskRecord#getRootActivity()} when all activities
+ * Test that no activity is reported in {@link Task#getRootActivity()} when all activities
* in the task are finishing.
*/
@Test
public void testGetRootActivity_allFinishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -611,7 +609,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testIsRootActivity() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -628,7 +626,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testIsRootActivity_allFinishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -646,10 +644,10 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testGetTaskForActivity() {
- final TaskRecord task0 = getTestTask();
+ final Task task0 = getTestTask();
final ActivityRecord activity0 = task0.getChildAt(0);
- final TaskRecord task1 = getTestTask();
+ final Task task1 = getTestTask();
final ActivityRecord activity1 = task1.getChildAt(0);
assertEquals(task0.mTaskId,
@@ -664,7 +662,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testGetTaskForActivity_onlyRoot_finishing() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Make the current root activity finishing
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -687,7 +685,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Make the current root activity relinquish task identity
final ActivityRecord activity0 = task.getChildAt(0);
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -710,7 +708,7 @@ public class TaskRecordTests extends ActivityTestsBase {
*/
@Test
public void testGetTaskForActivity_notOnlyRoot() {
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
final ActivityRecord activity0 = task.getChildAt(0);
activity0.finishing = true;
@@ -731,12 +729,12 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test {@link TaskRecord#updateEffectiveIntent()}.
+ * Test {@link Task#updateEffectiveIntent()}.
*/
@Test
public void testUpdateEffectiveIntent() {
// Test simple case with a single activity.
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
final ActivityRecord activity0 = task.getChildAt(0);
spyOn(task);
@@ -745,13 +743,13 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test {@link TaskRecord#updateEffectiveIntent()} with root activity marked as finishing. This
+ * Test {@link Task#updateEffectiveIntent()} with root activity marked as finishing. This
* should make the task use the second activity when updating the intent.
*/
@Test
public void testUpdateEffectiveIntent_rootFinishing() {
// Test simple case with a single activity.
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
final ActivityRecord activity0 = task.getChildAt(0);
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
@@ -764,14 +762,14 @@ public class TaskRecordTests extends ActivityTestsBase {
}
/**
- * Test {@link TaskRecord#updateEffectiveIntent()} when all activities are finishing or
+ * Test {@link Task#updateEffectiveIntent()} when all activities are finishing or
* relinquishing task identity. In this case the root activity should still be used when
* updating the intent (legacy behavior).
*/
@Test
public void testUpdateEffectiveIntent_allFinishing() {
// Test simple case with a single activity.
- final TaskRecord task = getTestTask();
+ final Task task = getTestTask();
final ActivityRecord activity0 = task.getChildAt(0);
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
@@ -785,7 +783,7 @@ public class TaskRecordTests extends ActivityTestsBase {
verify(task).setIntent(eq(activity0));
}
- private TaskRecord getTestTask() {
+ private Task getTestTask() {
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
return stack.getChildAt(0);
}
@@ -796,7 +794,7 @@ public class TaskRecordTests extends ActivityTestsBase {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
final Configuration parentConfig = stack.getConfiguration();
parentConfig.windowConfiguration.setAppBounds(parentBounds);
@@ -808,7 +806,7 @@ public class TaskRecordTests extends ActivityTestsBase {
task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
}
- private byte[] serializeToBytes(TaskRecord r) throws IOException, XmlPullParserException {
+ private byte[] serializeToBytes(Task r) throws IOException, XmlPullParserException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
final XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(os, "UTF-8");
@@ -823,29 +821,29 @@ public class TaskRecordTests extends ActivityTestsBase {
}
}
- private TaskRecord restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
+ private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(reader);
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals(TASK_TAG, parser.getName());
- return TaskRecord.restoreFromXml(parser, mService.mStackSupervisor);
+ return Task.restoreFromXml(parser, mService.mStackSupervisor);
}
}
- private TaskRecord createTaskRecord(int taskId) {
- return new TaskRecord(mService, taskId, new Intent(), null, null, null,
+ private Task createTask(int taskId) {
+ return new Task(mService, taskId, new Intent(), null, null, null,
ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
null /*stack*/);
}
- private static class TestTaskRecordFactory extends TaskRecordFactory {
+ private static class TestTaskFactory extends TaskFactory {
private boolean mCreated = false;
@Override
- TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Intent intent, IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor, ActivityStack stack) {
mCreated = true;
@@ -853,7 +851,7 @@ public class TaskRecordTests extends ActivityTestsBase {
}
@Override
- TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+ Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Intent intent, ActivityManager.TaskDescription taskDescription,
ActivityStack stack) {
mCreated = true;
@@ -861,7 +859,7 @@ public class TaskRecordTests extends ActivityTestsBase {
}
@Override
- TaskRecord create(ActivityTaskManagerService service, int taskId, Intent intent,
+ Task create(ActivityTaskManagerService service, int taskId, Intent intent,
Intent affinityIntent, String affinity, String rootAffinity,
ComponentName realActivity,
ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
@@ -879,7 +877,7 @@ public class TaskRecordTests extends ActivityTestsBase {
}
@Override
- TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+ Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
throws IOException, XmlPullParserException {
mCreated = true;
return null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index f56839b28add..8617fb258ba1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -121,7 +121,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
false /* includingParents */);
// Move the task of {@code mDisplayContent} to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task, true /* includingParents */);
+ stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent);
assertEquals("The testing DisplayContent should be moved to top with task",
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 98d4e6667b31..40ce36324578 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -58,12 +58,12 @@ public class TaskStackTests extends WindowTestsBase {
final Task task2 = createTaskInStack(stack, 1 /* userId */);
// Current user task should be moved to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task1, false /* includingParents */);
+ stack.positionChildAt(WindowContainer.POSITION_TOP, task1, false /* includingParents */);
assertEquals(stack.mChildren.get(0), task2);
assertEquals(stack.mChildren.get(1), task1);
// Non-current user won't be moved to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task2, false /* includingParents */);
+ stack.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
assertEquals(stack.mChildren.get(0), task2);
assertEquals(stack.mChildren.get(1), task1);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 6a9413716a89..e1475a453330 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -37,8 +37,8 @@ public class TestIWindow extends IWindow.Stub {
}
@Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
- Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
+ public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
+ Rect stableInsets, boolean reportDraw, MergedConfiguration mergedConfig,
Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 05457ccd7303..814004522b28 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -221,6 +221,32 @@ public class WindowContainerTests extends WindowTestsBase {
}
@Test
+ public void testRemoveImmediatelyClearsLastSurfacePosition() {
+ reset(mTransaction);
+ try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
+ final WindowContainer<WindowContainer> child1 = new WindowContainer(mWm);
+ child1.setBounds(1, 1, 10, 10);
+
+ top.addChild(child1, 0);
+ assertEquals(1, child1.getLastSurfacePosition().x);
+ assertEquals(1, child1.getLastSurfacePosition().y);
+
+ WindowContainer child11 = new WindowContainer(mWm);
+ child1.addChild(child11, 0);
+
+ child1.setBounds(2, 2, 20, 20);
+ assertEquals(2, child1.getLastSurfacePosition().x);
+ assertEquals(2, child1.getLastSurfacePosition().y);
+
+ child1.removeImmediately();
+ assertEquals(0, child1.getLastSurfacePosition().x);
+ assertEquals(0, child1.getLastSurfacePosition().y);
+ assertEquals(0, child11.getLastSurfacePosition().x);
+ assertEquals(0, child11.getLastSurfacePosition().y);
+ }
+ }
+
+ @Test
public void testAddChildByIndex() {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 428d869fe3cd..0b8b6a1f23ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -150,7 +150,7 @@ public class WindowFrameTests extends WindowTestsBase {
// When mFrame extends past cf, the content insets are
// the difference between mFrame and ContentFrame. Visible
// and stable frames work the same way.
- w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
@@ -186,7 +186,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
- w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf);
w.computeFrameLw();
assertFrame(w, 0, 0, 1000, 1000);
@@ -274,7 +274,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
w.computeFrameLw();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
@@ -287,7 +287,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int cfRight = logicalWidth / 2;
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
- windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+ windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
w.computeFrameLw();
assertEquals(resolvedTaskBounds, w.getFrameLw());
int contentInsetRight = resolvedTaskBounds.right - cfRight;
@@ -306,7 +306,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
task.setOverrideDisplayedBounds(resolvedTaskBounds);
task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
- windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+ windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
w.computeFrameLw();
assertEquals(resolvedTaskBounds, w.getFrameLw());
contentInsetRight = insetRight - cfRight;
@@ -328,7 +328,6 @@ public class WindowFrameTests extends WindowTestsBase {
final int logicalHeight = displayInfo.logicalHeight;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final Rect df = pf;
- final Rect of = df;
final Rect cf = new Rect(pf);
// Produce some insets
cf.top += displayInfo.logicalWidth / 10;
@@ -339,7 +338,7 @@ public class WindowFrameTests extends WindowTestsBase {
Rect dcf = new Rect(cf);
final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ windowFrames.setFrames(pf, df, cf, vf, dcf, sf);
w.computeFrameLw();
assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
@@ -353,7 +352,7 @@ public class WindowFrameTests extends WindowTestsBase {
// we need to account for the fact the windows surface will be made
// fullscreen and thus also make the crop fullscreen.
- windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
w.mAttrs.width = logicalWidth / 2;
w.mAttrs.height = logicalHeight / 2;
@@ -395,7 +394,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
w.computeFrameLw();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
@@ -413,7 +412,7 @@ public class WindowFrameTests extends WindowTestsBase {
pf.set(0, 0, logicalWidth, logicalHeight);
task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setBounds(null);
- windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
+ windowFrames.setFrames(pf, pf, cf, cf, pf, cf);
w.computeFrameLw();
assertFrame(w, cf);
assertContentFrame(w, cf);
@@ -434,7 +433,7 @@ public class WindowFrameTests extends WindowTestsBase {
pf.width(), pf.height());
final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
w.computeFrameLw();
@@ -461,7 +460,7 @@ public class WindowFrameTests extends WindowTestsBase {
pf.width(), pf.height());
final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
+ windowFrames.setFrames(pf, pf, pf, pf, pf, pf);
windowFrames.setDisplayCutout(cutout);
w.computeFrameLw();
@@ -501,7 +500,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect winRect = new Rect(200, 200, 300, 500);
task.setBounds(winRect);
- w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
w.computeFrameLw();
final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
@@ -514,7 +513,7 @@ public class WindowFrameTests extends WindowTestsBase {
winRect.bottom = 600;
task.setBounds(winRect);
w.setBounds(winRect);
- w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
+ w.getWindowFrames().setFrames(pf, df, cf, vf, dcf, sf);
w.computeFrameLw();
assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
@@ -524,7 +523,7 @@ public class WindowFrameTests extends WindowTestsBase {
assertVisibleFrame(w, expected);
// Check that it's moved back without ime insets
- w.getWindowFrames().setFrames(pf, df, of, pf, pf, dcf, sf, mEmptyRect);
+ w.getWindowFrames().setFrames(pf, df, pf, pf, dcf, sf);
w.computeFrameLw();
assertEquals(winRect, w.getFrameLw());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e1f92dddf053..0b7cbceb8f95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -383,11 +383,11 @@ public class WindowStateTests extends WindowTestsBase {
@Test
public void testCanAffectSystemUiFlags() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- app.mToken.setHidden(false);
+ app.mActivityRecord.setVisible(true);
assertTrue(app.canAffectSystemUiFlags());
- app.mToken.setHidden(true);
+ app.mActivityRecord.setVisible(false);
assertFalse(app.canAffectSystemUiFlags());
- app.mToken.setHidden(false);
+ app.mActivityRecord.setVisible(true);
app.mAttrs.alpha = 0.0f;
assertFalse(app.canAffectSystemUiFlags());
}
@@ -395,7 +395,7 @@ public class WindowStateTests extends WindowTestsBase {
@Test
public void testCanAffectSystemUiFlags_disallow() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- app.mToken.setHidden(false);
+ app.mActivityRecord.setVisible(true);
assertTrue(app.canAffectSystemUiFlags());
app.getTask().setCanAffectSystemUiFlags(false);
assertFalse(app.canAffectSystemUiFlags());
@@ -569,7 +569,7 @@ public class WindowStateTests extends WindowTestsBase {
@Test
public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
- win0.mActivityRecord.hiddenRequested = true;
+ win0.mActivityRecord.mVisibleRequested = false;
assertTrue(win0.cantReceiveTouchInput());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 11dc1babd21d..26743c842122 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -35,7 +35,7 @@ class WindowTestUtils {
/** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
static Task createTaskInStack(WindowManagerService service, ActivityStack stack, int userId) {
synchronized (service.mGlobalLock) {
- final TaskRecord task = new ActivityTestsBase.TaskBuilder(
+ final Task task = new ActivityTestsBase.TaskBuilder(
stack.mStackSupervisor)
.setUserId(userId)
.setStack(stack)
@@ -74,8 +74,8 @@ class WindowTestUtils {
private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
activity.onDisplayChanged(dc);
activity.setOccludesParent(true);
- activity.setHidden(false);
- activity.hiddenRequested = false;
+ activity.setVisible(true);
+ activity.mVisibleRequested = true;
}
static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 24b40460066b..3ecf8d73d0a6 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -25,8 +25,11 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import com.android.internal.telecom.IVideoProvider;
+
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
@@ -2132,13 +2135,22 @@ public final class Call {
cannedTextResponsesChanged = true;
}
- VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
- mTargetSdkVersion);
- boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
- !Objects.equals(mVideoCallImpl, newVideoCallImpl);
+ IVideoProvider previousVideoProvider = mVideoCallImpl == null ? null :
+ mVideoCallImpl.getVideoProvider();
+ IVideoProvider newVideoProvider = parcelableCall.getVideoProvider();
+
+ // parcelableCall.isVideoCallProviderChanged is only true when we have a video provider
+ // specified; so we should check if the actual IVideoProvider changes as well.
+ boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged()
+ && !Objects.equals(previousVideoProvider, newVideoProvider);
if (videoCallChanged) {
- mVideoCallImpl = newVideoCallImpl;
+ if (mVideoCallImpl != null) {
+ mVideoCallImpl.destroy();
+ }
+ mVideoCallImpl = parcelableCall.isVideoCallProviderChanged() ?
+ parcelableCall.getVideoCallImpl(mCallingPackage, mTargetSdkVersion) : null;
}
+
if (mVideoCallImpl != null) {
mVideoCallImpl.setVideoState(getDetails().getVideoState());
}
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index ef1c790dcc83..b91787ccff83 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -106,8 +106,14 @@ public abstract class CallScreeningService extends Service {
SomeArgs args = (SomeArgs) msg.obj;
try {
mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
- onScreenCall(
- Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
+ Call.Details callDetails = Call.Details
+ .createFromParcelableCall((ParcelableCall) args.arg2);
+ onScreenCall(callDetails);
+ if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) {
+ mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
+ }
+ } catch (RemoteException e) {
+ Log.w(this, "Exception when screening call: " + e);
} finally {
args.recycle();
}
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index aa50991b118c..fdc324308d7a 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -21,6 +21,7 @@ import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -225,6 +226,10 @@ public final class ParcelableCall implements Parcelable {
return mVideoCall;
}
+ public IVideoProvider getVideoProvider() {
+ return mVideoCallProvider;
+ }
+
public boolean getIsRttCallChanged() {
return mIsRttCallChanged;
}
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index cb74012e2b81..4a1aa0a8ffa4 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -32,6 +32,8 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import java.util.NoSuchElementException;
+
/**
* Implementation of a Video Call, which allows InCallUi to communicate commands to the underlying
* {@link Connection.VideoProvider}, and direct callbacks from the
@@ -53,7 +55,11 @@ public class VideoCallImpl extends VideoCall {
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- mVideoProvider.asBinder().unlinkToDeath(this, 0);
+ try {
+ mVideoProvider.asBinder().unlinkToDeath(this, 0);
+ } catch (NoSuchElementException nse) {
+ // Already unlinked in destroy below.
+ }
}
};
@@ -222,6 +228,11 @@ public class VideoCallImpl extends VideoCall {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
public void destroy() {
unregisterCallback(mCallback);
+ try {
+ mVideoProvider.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException nse) {
+ // Already unlinked in binderDied above.
+ }
}
/** {@inheritDoc} */
@@ -353,4 +364,12 @@ public class VideoCallImpl extends VideoCall {
public void setVideoState(int videoState) {
mVideoState = videoState;
}
+
+ /**
+ * Get the video provider binder.
+ * @return the video provider binder.
+ */
+ public IVideoProvider getVideoProvider() {
+ return mVideoProvider;
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 570fbb3fd4b6..864bf03c1448 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -505,7 +505,7 @@ public class TelephonyManager {
*/
@Nullable
public TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
- int subId = getSubIdForPhoneAccountHandle(phoneAccountHandle);
+ int subId = getSubscriptionId(phoneAccountHandle);
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
return null;
}
@@ -4226,6 +4226,7 @@ public class TelephonyManager {
* @hide
* nobody seems to call this.
*/
+ @UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getLine1AlphaTag() {
@@ -9633,7 +9634,7 @@ public class TelephonyManager {
* permission.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getSubIdForPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
+ public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) {
int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
try {
ITelephony service = getITelephony();
@@ -9642,7 +9643,7 @@ public class TelephonyManager {
phoneAccountHandle, mContext.getOpPackageName());
}
} catch (RemoteException ex) {
- Log.e(TAG, "getSubIdForPhoneAccountHandle RemoteException", ex);
+ Log.e(TAG, "getSubscriptionId RemoteException", ex);
ex.rethrowAsRuntimeException();
}
return retval;
@@ -10765,6 +10766,7 @@ public class TelephonyManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public int getCarrierIdListVersion() {
try {
@@ -11653,6 +11655,7 @@ public class TelephonyManager {
*
* @hide
*/
+ @UnsupportedAppUsage
@TestApi
public Pair<Integer, Integer> getRadioHalVersion() {
try {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 0025c7acb18c..cb66a9650f2f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -189,6 +189,29 @@ public class EuiccManager {
"android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
/**
+ * Intent action sent by a carrier app to launch the eSIM activation flow provided by the LPA UI
+ * (LUI). The carrier app must send this intent with one of the following:
+ *
+ * <p>{@link #EXTRA_USE_QR_SCANNER} not set or set to false: The LPA should try to get an
+ * activation code from the carrier app by binding to the carrier app service implementing
+ * {@link android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
+ * <p>{@link #EXTRA_USE_QR_SCANNER} set to true: The LPA should launch a QR scanner for the user
+ * to scan an eSIM profile QR code.
+ *
+ * <p>Upon completion, the LPA should return one of the following results to the carrier app:
+ *
+ * <p>{@code Activity.RESULT_OK}: The LPA has succeeded in downloading the new eSIM profile.
+ * <p>{@code Activity.RESULT_CANCELED}: The carrier app should treat this as if the user pressed
+ * the back button.
+ * <p>Anything else: The carrier app should treat this as an error.
+ *
+ * <p>LPA needs to check if caller's package name is allowed to perform this action.
+ **/
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_START_EUICC_ACTIVATION =
+ "android.telephony.euicc.action.START_EUICC_ACTIVATION";
+
+ /**
* Result code for an operation indicating that the operation succeeded.
*/
public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -342,10 +365,20 @@ public class EuiccManager {
*
* @hide
*/
- // TODO: Make this a @SystemApi.
+ @SystemApi
public static final String EXTRA_PHYSICAL_SLOT_ID =
"android.telephony.euicc.extra.PHYSICAL_SLOT_ID";
+
+ /**
+ * Key for an extra set on actions {@link #ACTION_START_EUICC_ACTIVATION} providing a boolean
+ * value of whether to start eSIM activation with QR scanner.
+ *
+ * <p>Expected type of the extra data: boolean
+ **/
+ public static final String EXTRA_USE_QR_SCANNER =
+ "android.telephony.euicc.extra.USE_QR_SCANNER";
+
/**
* Optional meta-data attribute for a carrier app providing an icon to use to represent the
* carrier. If not provided, the app's launcher icon will be used as a fallback.
@@ -830,7 +863,7 @@ public class EuiccManager {
* @param callbackIntent a PendingIntent to launch when the operation completes.
*
* @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
- * and use {@link #eraseSubscriptionsWithOptions(int, PendingIntent)} instead
+ * and use {@link #eraseSubscriptions(int, PendingIntent)} instead
*
* @hide
*/
@@ -862,7 +895,7 @@ public class EuiccManager {
*/
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
- public void eraseSubscriptionsWithOptions(
+ public void eraseSubscriptions(
@ResetOption int options, @NonNull PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index eb0e2f7b8786..5fd0af564d34 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -979,25 +979,25 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* Get the status of the MmTel Feature registered on this subscription.
+ * @param executor The executor that will be used to call the callback.
* @param callback A callback containing an Integer describing the current state of the
* MmTel feature, Which will be one of the following:
* {@link ImsFeature#STATE_UNAVAILABLE},
* {@link ImsFeature#STATE_INITIALIZING},
* {@link ImsFeature#STATE_READY}. Will be called using the executor
* specified when the service state has been retrieved from the IMS service.
- * @param executor The executor that will be used to call the callback.
* @throws ImsException if the IMS service associated with this subscription is not available or
* the IMS service is not available.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void getFeatureState(@NonNull @ImsFeature.ImsState Consumer<Integer> callback,
- @NonNull @CallbackExecutor Executor executor) throws ImsException {
- if (callback == null) {
- throw new IllegalArgumentException("Must include a non-null Consumer.");
- }
+ public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
+ @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+ if (callback == null) {
+ throw new IllegalArgumentException("Must include a non-null Consumer.");
+ }
try {
getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
@Override
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 0b5d4460612d..aa4174ad40f4 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -27,7 +27,10 @@ java_sdk_library {
":framework-core-sources-for-test-mock",
":framework_native_aidl",
],
- libs: ["framework-all"],
+ libs: [
+ "framework-all",
+ "app-compat-annotations",
+ ],
api_packages: [
"android.test.mock",
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index a70152c8b732..8283019a10ec 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -16,6 +16,8 @@
package android.test.mock;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -130,17 +132,47 @@ public class MockContentResolver extends ContentResolver {
}
/**
- * Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
- * ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
- * The method hides providers linked to MockContentResolver from other observers in the system.
+ * Overrides the behavior from the parent class to completely ignore any
+ * content notifications sent to this object. This effectively hides clients
+ * from observers elsewhere in the system.
+ */
+ @Override
+ public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
+ }
+
+ /**
+ * Overrides the behavior from the parent class to completely ignore any
+ * content notifications sent to this object. This effectively hides clients
+ * from observers elsewhere in the system.
*
- * @param uri (Ignored) The uri of the content provider.
- * @param observer (Ignored) The observer that originated the change.
- * @param syncToNetwork (Ignored) If true, attempt to sync the change to the network.
+ * @deprecated callers should consider migrating to
+ * {@link #notifyChange(Uri, ContentObserver, int)}, as it
+ * offers support for many more options than just
+ * {@link #NOTIFY_SYNC_TO_NETWORK}.
*/
@Override
- public void notifyChange(Uri uri,
- ContentObserver observer,
+ @Deprecated
+ public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
boolean syncToNetwork) {
}
+
+ /**
+ * Overrides the behavior from the parent class to completely ignore any
+ * content notifications sent to this object. This effectively hides clients
+ * from observers elsewhere in the system.
+ */
+ @Override
+ public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
+ @NotifyFlags int flags) {
+ }
+
+ /**
+ * Overrides the behavior from the parent class to completely ignore any
+ * content notifications sent to this object. This effectively hides clients
+ * from observers elsewhere in the system.
+ */
+ @Override
+ public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ @NotifyFlags int flags) {
+ }
}
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
index db2f659c655b..883c172e4990 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -27,8 +27,8 @@ import android.os.SystemClock;
import android.util.EventLog;
import android.util.EventLog.Event;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import dalvik.system.DexClassLoader;
@@ -91,7 +91,7 @@ public final class DynamicCodeLoggerIntegrationTests {
@BeforeClass
public static void setUpAll() {
- sContext = InstrumentationRegistry.getTargetContext();
+ sContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
sMyUid = android.os.Process.myUid();
}
@@ -331,7 +331,7 @@ public final class DynamicCodeLoggerIntegrationTests {
// Abstract out the logic for running a native code loading test multiple times if needed and
// leaving time for audit messages to reach the log.
- private abstract class TestNativeCodeWithRetries {
+ private abstract static class TestNativeCodeWithRetries {
String mExpectedContentHash;
String mExpectedNameHash;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
index fd31aa531107..e033d0ab9578 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
@@ -78,6 +78,7 @@ class CommonTransitions {
return TransitionRunner.newBuilder()
.withTag("OpenAppWarm_" + testApp.getLauncherName()
+ rotationToString(beginRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBeforeAll(() -> setRotation(device, beginRotation))
.runBeforeAll(testApp::open)
@@ -94,6 +95,7 @@ class CommonTransitions {
device) {
return TransitionRunner.newBuilder()
.withTag("closeAppWithBackKey_" + testApp.getLauncherName())
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(testApp::open)
.runBefore(device::waitForIdle)
@@ -108,6 +110,7 @@ class CommonTransitions {
device) {
return TransitionRunner.newBuilder()
.withTag("closeAppWithHomeKey_" + testApp.getLauncherName())
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(testApp::open)
.runBefore(device::waitForIdle)
@@ -123,6 +126,7 @@ class CommonTransitions {
return TransitionRunner.newBuilder()
.withTag("OpenAppCold_" + testApp.getLauncherName()
+ rotationToString(beginRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(device::pressHome)
.runBeforeAll(() -> setRotation(device, beginRotation))
@@ -140,6 +144,7 @@ class CommonTransitions {
.withTag("changeAppRotation_" + testApp.getLauncherName()
+ rotationToString(beginRotation) + "_" +
rotationToString(endRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBeforeAll(testApp::open)
.runBefore(() -> setRotation(device, beginRotation))
@@ -156,6 +161,7 @@ class CommonTransitions {
rotationToString(beginRotation) + "_" + rotationToString(endRotation);
return TransitionRunner.newBuilder()
.withTag(testTag)
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBeforeAll(() -> {
context.startActivity(intent);
@@ -173,6 +179,7 @@ class CommonTransitions {
static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device) {
return TransitionRunner.newBuilder()
.withTag("appToSplitScreen_" + testApp.getLauncherName())
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(testApp::open)
.runBefore(device::waitForIdle)
@@ -186,6 +193,7 @@ class CommonTransitions {
static TransitionBuilder splitScreenToLauncher(IAppHelper testApp, UiDevice device) {
return TransitionRunner.newBuilder()
.withTag("splitScreenToLauncher_" + testApp.getLauncherName())
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(testApp::open)
.runBefore(device::waitForIdle)
@@ -200,6 +208,7 @@ class CommonTransitions {
return TransitionRunner.newBuilder()
.withTag("editTextSetFocus_" + testApp.getLauncherName()
+ rotationToString(beginRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(device::pressHome)
.runBefore(() -> setRotation(device, beginRotation))
@@ -218,6 +227,7 @@ class CommonTransitions {
+ rotationToString(beginRotation);
return TransitionRunner.newBuilder()
.withTag(testTag)
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBeforeAll(() -> setRotation(device, beginRotation))
.runBeforeAll(() -> clearRecents(device))
@@ -246,6 +256,7 @@ class CommonTransitions {
return TransitionRunner.newBuilder()
.withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()
+ rotationToString(beginRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(device::pressHome)
.runBefore(() -> setRotation(device, beginRotation))
@@ -262,6 +273,7 @@ class CommonTransitions {
return TransitionRunner.newBuilder()
.withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()
+ rotationToString(beginRotation))
+ .recordAllRuns()
.runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
.runBefore(device::pressHome)
.runBefore(() -> setRotation(device, beginRotation))
diff --git a/tests/WindowManagerStressTest/AndroidManifest.xml b/tests/WindowManagerStressTest/AndroidManifest.xml
deleted file mode 100644
index 17e0f15c29a9..000000000000
--- a/tests/WindowManagerStressTest/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="test.windowmanagerstresstest">
-
- <application
- android:allowBackup="false"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/WindowManagerStressTest/res/layout/activity_main.xml b/tests/WindowManagerStressTest/res/layout/activity_main.xml
deleted file mode 100644
index 6cf82691155c..000000000000
--- a/tests/WindowManagerStressTest/res/layout/activity_main.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="test.amslam.MainActivity">
-
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/run"
- android:text="@string/run" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/output" />
-
-</LinearLayout>
diff --git a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec6..000000000000
--- a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379..000000000000
--- a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91..000000000000
--- a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd748..000000000000
--- a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e138434..000000000000
--- a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/values/dimens.xml b/tests/WindowManagerStressTest/res/values/dimens.xml
deleted file mode 100644
index ed4ccbcc700f..000000000000
--- a/tests/WindowManagerStressTest/res/values/dimens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!-- 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.
--->
-<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
diff --git a/tests/WindowManagerStressTest/res/values/strings.xml b/tests/WindowManagerStressTest/res/values/strings.xml
deleted file mode 100644
index cef05dcb6584..000000000000
--- a/tests/WindowManagerStressTest/res/values/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
- ~ Copyright (C) 2017 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <string name="app_name">WmSlam</string>
- <string name="run">Run</string>
-</resources>
diff --git a/tests/WindowManagerStressTest/res/values/styles.xml b/tests/WindowManagerStressTest/res/values/styles.xml
deleted file mode 100644
index 0983b2535878..000000000000
--- a/tests/WindowManagerStressTest/res/values/styles.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!-- 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.
--->
-<resources>
- <!-- Base application theme. -->
- <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
- <!-- Customize your theme here. -->
- <item name="android:colorPrimary">@color/colorPrimary</item>
- <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
- <item name="android:colorAccent">@color/colorAccent</item>
- </style>
-</resources>
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
deleted file mode 100644
index 85646987940f..000000000000
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package test.windowmanagerstresstest;
-
-import android.app.Activity;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.MergedConfiguration;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.IWindowSession;
-import android.view.InsetsState;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
-import android.widget.TextView;
-
-import com.android.internal.view.BaseIWindow;
-
-import java.util.ArrayList;
-
-public class MainActivity extends Activity {
-
- private static final String TAG = "WmSlam";
-
- private TextView mOutput;
- private volatile boolean finished;
- private final ArrayList<BaseIWindow> mWindows = new ArrayList<>();
- private final LayoutParams mLayoutParams = new LayoutParams();
- private final Rect mTmpRect = new Rect();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mOutput = (TextView) findViewById(R.id.output);
-
- findViewById(R.id.run).setOnClickListener(view -> {
- view.setEnabled(false);
- mOutput.setText("");
- startBatch();
- });
- mLayoutParams.token = getActivityToken();
- }
-
- void startBatch() {
- new Thread(() -> {
- finished = false;
- addWindows();
- startCpuRunnables();
- for (int i = 0; i < 5; i++) {
- final long time = SystemClock.uptimeMillis();
- slamWm();
- log("Total: " + (SystemClock.uptimeMillis() - time) + " ms");
- }
- removeWindows();
- finished = true;
- }).start();
- }
-
- void startCpuRunnables() {
- for (int i = 0; i < 10; i++) {
- new Thread(mUseCpuRunnable).start();
- }
- }
-
- private final Runnable mUseCpuRunnable = new Runnable() {
- @Override
- public void run() {
- while (!finished) {
- }
- }
- };
-
- private void log(String text) {
- mOutput.post(() -> mOutput.append(text + "\n"));
- Log.d(TAG, text);
- }
-
- private void slamWm() {
- ArrayList<Thread> threads = new ArrayList<>();
- for (int i = 0; i < 20; i++) {
- for (BaseIWindow window : mWindows) {
- Thread t = new Thread(() -> {
- try {
- WindowManagerGlobal.getWindowSession().relayout(window,
- window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect,
- mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
- new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
- new SurfaceControl(), new InsetsState());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- });
- threads.add(t);
- t.start();
- }
- }
- for (Thread t : threads) {
- try {
- t.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- void addWindows() {
- for (int i = 0; i < 50; i++) {
- final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
- layoutParams.token = getActivityToken();
- final BaseIWindow window = new BaseIWindow();
- final IWindowSession session = WindowManagerGlobal.getWindowSession();
- final Rect tmpRect = new Rect();
- try {
- final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq,
- layoutParams, View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect,
- new InsetsState());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- mWindows.add(window);
- }
- }
-
- void removeWindows() {
- for (BaseIWindow window : mWindows) {
- try {
- WindowManagerGlobal.getWindowSession().remove(window);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
-}
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index 91b3cd9e791f..4dd3b5a23d7a 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -17,7 +17,6 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
package="com.android.server.net.integrationtests">
<!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
@@ -26,13 +25,19 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<!-- ConnectivityService sends notifications to BatteryStats -->
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <!-- Reading network status -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ <!-- Reading DeviceConfig flags -->
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
<!-- This manifest is merged with the base manifest of the real NetworkStack app.
Remove the NetworkStackService from the base (real) manifest, and replace with a test
service that responds to the same intent -->
- <service android:name="com.android.server.NetworkStackService" tools:node="remove"/>
<service android:name=".TestNetworkStackService"
android:process="com.android.server.net.integrationtests.testnetworkstack">
<intent-filter>
@@ -45,9 +50,9 @@
<action android:name=".INetworkStackInstrumentation"/>
</intent-filter>
</service>
- <service tools:replace="android:process"
- android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
- android:process="com.android.server.net.integrationtests.testnetworkstack"/>
+ <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+ android:process="com.android.server.net.integrationtests.testnetworkstack"
+ android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 1f2bb0ac05ee..84c5784d3fa8 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -46,7 +46,6 @@ import androidx.test.runner.AndroidJUnit4;
import libcore.util.HexEncoding;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -202,14 +201,29 @@ public class InetDiagSocketTest {
checkGetConnectionOwnerUid("::1", "::1");
}
- @Ignore("Times out on Marlin/Sailfish")
/* Verify fix for b/141603906 */
@Test
public void testB141603906() throws Exception {
final InetSocketAddress src = new InetSocketAddress(0);
final InetSocketAddress dst = new InetSocketAddress(0);
- for (int i = 1; i <= 100000; i++) {
- mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
+ final int numThreads = 8;
+ final int numSockets = 5000;
+ final Thread[] threads = new Thread[numThreads];
+
+ for (int i = 0; i < numThreads; i++) {
+ threads[i] = new Thread(() -> {
+ for (int j = 0; j < numSockets; j++) {
+ mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
+ }
+ });
+ }
+
+ for (Thread thread : threads) {
+ thread.start();
+ }
+
+ for (Thread thread : threads) {
+ thread.join();
}
}
diff --git a/tests/touchlag/Android.bp b/tests/touchlag/Android.bp
deleted file mode 100644
index 092eea918b1d..000000000000
--- a/tests/touchlag/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-cc_test {
- name: "test-touchlag",
- gtest: false,
- srcs: ["touchlag.cpp"],
- shared_libs: [
- "libcutils",
- "libutils",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp
deleted file mode 100644
index 9264a254ed24..000000000000
--- a/tests/touchlag/touchlag.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <cutils/memory.h>
-#include <asm-generic/mman.h>
-#include <sys/mman.h>
-#include <utils/threads.h>
-#include <unistd.h>
-#include <math.h>
-
-using namespace android;
-
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
-struct Buffer {
- size_t w;
- size_t h;
- size_t s;
- union {
- void* addr;
- uint32_t* pixels;
- };
-};
-
-void clearBuffer(Buffer* buf, uint32_t pixel) {
- android_memset32(buf->pixels, pixel, buf->s * buf->h * 4);
-}
-
-void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
- if (y>0 && y<ssize_t(buf->h)) {
- uint32_t* bits = buf->pixels + y * buf->s;
- if (x>=0 && x<ssize_t(buf->w)) {
- bits[x] = pixel;
- }
- ssize_t W(w);
- if ((x+W)>=0 && (x+W)<ssize_t(buf->w)) {
- bits[x+W] = pixel;
- }
- }
-}
-
-void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
- if (y>0 && y<ssize_t(buf->h)) {
- ssize_t W(w);
- if (x<0) {
- W += x;
- x = 0;
- }
- if (x+w > buf->w) {
- W = buf->w - x;
- }
- if (W>0) {
- uint32_t* bits = buf->pixels + y * buf->s + x;
- android_memset32(bits, pixel, W*4);
- }
- }
-}
-
-void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) {
- ssize_t W(w), H(h);
- if (x<0) {
- w += x;
- x = 0;
- }
- if (y<0) {
- h += y;
- y = 0;
- }
- if (x+w > buf->w) W = buf->w - x;
- if (y+h > buf->h) H = buf->h - y;
- if (W>0 && H>0) {
- uint32_t* bits = buf->pixels + y * buf->s + x;
- for (ssize_t i=0 ; i<H ; i++) {
- android_memset32(bits, pixel, W*4);
- bits += buf->s;
- }
- }
-}
-
-void drawCircle(Buffer* buf, uint32_t pixel,
- size_t x0, size_t y0, size_t radius, bool filled = false) {
- ssize_t f = 1 - radius;
- ssize_t ddF_x = 1;
- ssize_t ddF_y = -2 * radius;
- ssize_t x = 0;
- ssize_t y = radius;
- if (filled) {
- drawHLine(buf, pixel, x0-radius, y0, 2*radius);
- } else {
- drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius);
- }
- while (x < y) {
- if (f >= 0) {
- y--;
- ddF_y += 2;
- f += ddF_y;
- }
- x++;
- ddF_x += 2;
- f += ddF_x;
- if (filled) {
- drawHLine(buf, pixel, x0-x, y0+y, 2*x);
- drawHLine(buf, pixel, x0-x, y0-y, 2*x);
- drawHLine(buf, pixel, x0-y, y0+x, 2*y);
- drawHLine(buf, pixel, x0-y, y0-x, 2*y);
- } else {
- drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x);
- drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x);
- drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y);
- drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y);
- }
- }
-}
-
-class TouchEvents {
- class EventThread : public Thread {
- int fd;
-
- virtual bool threadLoop() {
- input_event event;
- int first_down = 0;
- do {
- read(fd, &event, sizeof(event));
- if (event.type == EV_ABS) {
- if (event.code == ABS_MT_TRACKING_ID) {
- down = event.value == -1 ? 0 : 1;
- first_down = down;
- }
- if (event.code == ABS_MT_POSITION_X) {
- x = event.value;
- }
- if (event.code == ABS_MT_POSITION_Y) {
- y = event.value;
- }
- }
- } while (event.type == EV_SYN);
- return true;
- }
-
- public:
- int x, y, down;
- EventThread() : Thread(false),
- x(0), y(0), down(0)
- {
- fd = open("/dev/input/event1", O_RDONLY);
- }
-};
- sp<EventThread> thread;
-
-public:
- TouchEvents() {
- thread = new EventThread();
- thread->run("EventThread", PRIORITY_URGENT_DISPLAY);
- }
-
- int getMostRecentPosition(int* x, int* y) {
- *x = thread->x;
- *y = thread->y;
- return thread->down;
- }
-};
-
-
-struct Queue {
- struct position {
- int x, y;
- };
- int index;
- position q[16];
- Queue() : index(0) { }
- void push(int x, int y) {
- index++;
- index &= 0xF;
- q[index].x = x;
- q[index].y = y;
- }
- void get(int lag, int* x, int* y) {
- const int i = (index - lag) & 0xF;
- *x = q[i].x;
- *y = q[i].y;
- }
-};
-
-extern char *optarg;
-extern int optind;
-extern int optopt;
-extern int opterr;
-extern int optreset;
-
-void usage(const char* name) {
- printf("\nusage: %s [-h] [-l lag]\n", name);
-}
-
-int main(int argc, char** argv) {
- fb_var_screeninfo vi;
- fb_fix_screeninfo fi;
-
- int lag = 0;
- int fd = open("/dev/graphics/fb0", O_RDWR);
- ioctl(fd, FBIOGET_VSCREENINFO, &vi);
- ioctl(fd, FBIOGET_FSCREENINFO, &fi);
- void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- Buffer framebuffer;
- framebuffer.w = vi.xres;
- framebuffer.h = vi.yres;
- framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3);
- framebuffer.addr = bits;
-
- int ch;
- while ((ch = getopt(argc, argv, "hl:")) != -1) {
- switch (ch) {
- case 'l':
- lag = atoi(optarg);
- break;
- case 'h':
- default:
- usage(argv[0]);
- exit(0);
- }
- }
- argc -= optind;
- argv += optind;
-
-
- TouchEvents touch;
- Queue queue;
-
-
- int x=0, y=0;
- int lag_x=0, lag_y=0;
-
- clearBuffer(&framebuffer, 0);
- while (true) {
- uint32_t crt = 0;
- ioctl(fd, FBIO_WAITFORVSYNC, &crt);
-
- // draw beam marker
- drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
- // erase screen
- if (lag) {
- drawCircle(&framebuffer, 0, lag_x, lag_y, 100);
- drawHLine(&framebuffer, 0, 0, lag_y, 32);
- }
- drawCircle(&framebuffer, 0, x, y, 100, true);
- drawHLine(&framebuffer, 0, 0, y, 32);
-
- // draw a line at y=1000
- drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w);
-
- // get touch events
- touch.getMostRecentPosition(&x, &y);
- queue.push(x, y);
- queue.get(lag, &lag_x, &lag_y);
-
- if (lag) {
- drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100);
- drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32);
- }
-
- drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true);
- drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32);
-
- // draw end of frame beam marker
- drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h);
- }
-
- close(fd);
- return 0;
-}
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index 05ba8f05ec67..806f4e37e22a 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -404,12 +404,15 @@ void WriteKeepSet(const KeepSet& keep_set, OutputStream* out, bool minimal_keep)
for (const auto& entry : keep_set.conditional_class_set_) {
std::set<UsageLocation> locations;
- bool can_be_conditional = true;
- for (const UsageLocation& location : entry.second) {
- can_be_conditional &= CollectLocations(location, keep_set, &locations);
+ bool can_be_conditional = false;
+ if (keep_set.conditional_keep_rules_) {
+ can_be_conditional = true;
+ for (const UsageLocation& location : entry.second) {
+ can_be_conditional &= CollectLocations(location, keep_set, &locations);
+ }
}
- if (keep_set.conditional_keep_rules_ && can_be_conditional) {
+ if (can_be_conditional) {
for (const UsageLocation& location : locations) {
printer.Print("# Referenced at ").Println(location.source.to_string());
printer.Print("-if class **.R$layout { int ")
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 30c24d37a494..90343d4798a7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2627,7 +2627,6 @@ public class WifiConfiguration implements Parcelable {
out.writeInt(apBand);
out.writeInt(apChannel);
BackupUtils.writeString(out, preSharedKey);
- BackupUtils.writeString(out, saePasswordId);
out.writeInt(getAuthType());
out.writeBoolean(hiddenSSID);
return baos.toByteArray();
@@ -2651,7 +2650,6 @@ public class WifiConfiguration implements Parcelable {
config.apBand = in.readInt();
config.apChannel = in.readInt();
config.preSharedKey = BackupUtils.readString(in);
- config.saePasswordId = BackupUtils.readString(in);
config.allowedKeyManagement.set(in.readInt());
if (version >= 3) {
config.hiddenSSID = in.readBoolean();
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index fd26817bfd79..60fe60438ce7 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -120,10 +120,12 @@ public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable {
new Creator<WifiAwareNetworkInfo>() {
@Override
public WifiAwareNetworkInfo createFromParcel(Parcel in) {
+ byte[] addr = in.createByteArray();
+ String interfaceName = in.readString();
+ int port = in.readInt();
+ int transportProtocol = in.readInt();
Inet6Address ipv6Addr;
try {
- byte[] addr = in.createByteArray();
- String interfaceName = in.readString();
NetworkInterface ni = null;
if (interfaceName != null) {
try {
@@ -135,11 +137,8 @@ public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable {
ipv6Addr = Inet6Address.getByAddress(null, addr, ni);
} catch (UnknownHostException e) {
e.printStackTrace();
- return null;
+ return new WifiAwareNetworkInfo(null);
}
- int port = in.readInt();
- int transportProtocol = in.readInt();
-
return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol);
}