summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp8
-rw-r--r--apex/blobstore/OWNERS4
-rw-r--r--apex/blobstore/TEST_MAPPING7
-rw-r--r--apex/media/framework/java/android/media/MediaController2.java3
-rw-r--r--apex/sdkextensions/Android.bp (renamed from apex/sdkext/Android.bp)19
-rw-r--r--apex/sdkextensions/OWNERS (renamed from apex/sdkext/OWNERS)0
-rw-r--r--apex/sdkextensions/TEST_MAPPING (renamed from apex/sdkext/TEST_MAPPING)3
-rw-r--r--apex/sdkextensions/com.android.sdkext.avbpubkey (renamed from apex/sdkext/com.android.sdkext.avbpubkey)bin1032 -> 1032 bytes
-rw-r--r--apex/sdkextensions/com.android.sdkext.pem (renamed from apex/sdkext/com.android.sdkext.pem)0
-rw-r--r--apex/sdkextensions/com.android.sdkext.pk8 (renamed from apex/sdkext/com.android.sdkext.pk8)bin2375 -> 2375 bytes
-rw-r--r--apex/sdkextensions/com.android.sdkext.x509.pem (renamed from apex/sdkext/com.android.sdkext.x509.pem)0
-rw-r--r--apex/sdkextensions/derive_sdk/Android.bp (renamed from apex/sdkext/derive_sdk/Android.bp)22
-rw-r--r--apex/sdkextensions/derive_sdk/derive_sdk.cpp (renamed from apex/sdkext/derive_sdk/derive_sdk.cpp)2
-rw-r--r--apex/sdkextensions/derive_sdk/derive_sdk.rc (renamed from apex/sdkext/derive_sdk/derive_sdk.rc)0
-rw-r--r--apex/sdkextensions/derive_sdk/sdk.proto (renamed from apex/sdkext/derive_sdk/sdk.proto)0
-rw-r--r--apex/sdkextensions/framework/Android.bp (renamed from apex/sdkext/framework/Android.bp)33
-rw-r--r--apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java (renamed from apex/sdkext/framework/java/android/os/ext/SdkExtensions.java)0
-rw-r--r--apex/sdkextensions/framework/java/android/os/ext/package.html (renamed from apex/sdkext/framework/java/android/os/ext/package.html)0
-rw-r--r--apex/sdkextensions/gen_sdkinfo.py (renamed from apex/sdkext/gen_sdkinfo.py)0
-rw-r--r--apex/sdkextensions/ld.config.txt (renamed from apex/sdkext/ld.config.txt)6
-rw-r--r--apex/sdkextensions/manifest.json (renamed from apex/sdkext/manifest.json)0
-rw-r--r--apex/sdkextensions/sdk.proto (renamed from apex/sdkext/sdk.proto)0
-rw-r--r--apex/sdkextensions/testing/Android.bp46
-rw-r--r--apex/sdkextensions/testing/test_manifest.json4
-rw-r--r--apex/statsd/aidl/android/os/IStatsManagerService.aidl40
-rw-r--r--apex/statsd/aidl/android/os/IStatsd.aidl12
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsManagerService.java110
-rw-r--r--api/current.txt71
-rwxr-xr-xapi/system-current.txt168
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/statsd/Android.bp23
-rw-r--r--cmds/statsd/src/StatsService.cpp43
-rw-r--r--cmds/statsd/src/StatsService.h9
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp22
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp102
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp18
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h2
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp7
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h2
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.cpp6
-rw-r--r--cmds/statsd/src/subscriber/SubscriberReporter.h3
-rw-r--r--cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp6
-rw-r--r--core/java/android/app/DownloadManager.java35
-rw-r--r--core/java/android/app/StatsManager.java28
-rw-r--r--core/java/android/app/StatusBarManager.java29
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java33
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/NetworkTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java2
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java2
-rw-r--r--core/java/android/content/ContentProvider.java78
-rw-r--r--core/java/android/content/ContentProviderResult.java8
-rw-r--r--core/java/android/content/ContentResolver.java68
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java44
-rw-r--r--core/java/android/hardware/usb/UsbManager.java12
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.java242
-rw-r--r--core/java/android/net/ConnectivityManager.java30
-rw-r--r--core/java/android/net/NetworkStats.java219
-rw-r--r--core/java/android/net/TrafficStats.java2
-rw-r--r--core/java/android/os/Parcel.java106
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java25
-rw-r--r--core/java/android/os/PersistableBundle.java47
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/TelephonyServiceManager.java145
-rw-r--r--core/java/android/os/TimestampedValue.java (renamed from core/java/android/util/TimestampedValue.java)5
-rw-r--r--core/java/android/os/UpdateEngine.java170
-rw-r--r--core/java/android/os/UpdateEngineCallback.java3
-rw-r--r--core/java/android/os/ZygoteProcess.java2
-rw-r--r--core/java/android/os/storage/StorageManager.java197
-rw-r--r--core/java/android/os/storage/StorageVolume.java11
-rw-r--r--core/java/android/provider/DocumentsContract.java4
-rw-r--r--core/java/android/provider/Settings.java28
-rw-r--r--core/java/android/provider/Telephony.java399
-rw-r--r--core/java/android/service/autofill/FillResponse.java10
-rw-r--r--core/java/android/telephony/WapPushManagerConnector.java178
-rw-r--r--core/java/android/util/Log.java20
-rw-r--r--core/java/android/util/NtpTrustedTime.java1
-rw-r--r--core/java/android/view/IDisplayWindowInsetsController.aidl48
-rw-r--r--core/java/android/view/IWindowManager.aidl14
-rw-r--r--core/java/android/view/InsetsState.java17
-rw-r--r--core/java/android/view/SurfaceView.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/view/WindowInsets.java43
-rw-r--r--core/java/android/view/WindowManagerGlobal.java6
-rw-r--r--core/java/com/android/internal/compat/AndroidBuildClassifier.java34
-rw-r--r--core/java/com/android/internal/compat/IOverrideValidator.aidl38
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl6
-rw-r--r--core/java/com/android/internal/compat/OverrideAllowedState.aidl19
-rw-r--r--core/java/com/android/internal/compat/OverrideAllowedState.java153
-rw-r--r--core/java/com/android/internal/infra/AndroidFuture.java90
-rw-r--r--core/java/com/android/internal/os/Zygote.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java2
-rw-r--r--core/java/com/android/internal/telephony/IWapPushManager.aidl (renamed from telephony/java/com/android/internal/telephony/IWapPushManager.aidl)13
-rw-r--r--core/java/com/android/internal/telephony/WapPushManagerParams.java72
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp12
-rw-r--r--core/jni/fd_utils.cpp42
-rw-r--r--core/proto/android/server/animationadapter.proto10
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/anim/screen_rotate_0_enter.xml40
-rw-r--r--core/res/res/anim/screen_rotate_0_exit.xml37
-rw-r--r--core/res/res/anim/screen_rotate_0_frame.xml25
-rw-r--r--core/res/res/anim/screen_rotate_180_enter.xml12
-rw-r--r--core/res/res/anim/screen_rotate_180_exit.xml12
-rw-r--r--core/res/res/anim/screen_rotate_alpha.xml4
-rw-r--r--core/res/res/anim/screen_rotate_minus_90_enter.xml26
-rw-r--r--core/res/res/anim/screen_rotate_minus_90_exit.xml32
-rw-r--r--core/res/res/anim/screen_rotate_plus_90_enter.xml25
-rw-r--r--core/res/res/anim/screen_rotate_plus_90_exit.xml32
-rw-r--r--core/res/res/interpolator/screen_rotation_alpha_in.xml22
-rw-r--r--core/res/res/interpolator/screen_rotation_alpha_out.xml22
-rw-r--r--core/res/res/values/config.xml18
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java2
-rw-r--r--core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java4
-rw-r--r--core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java2
-rw-r--r--core/tests/coretests/src/android/os/TimestampedValueTest.java (renamed from core/tests/coretests/src/android/util/TimestampedValueTest.java)4
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java21
-rw-r--r--core/tests/coretests/src/android/view/WindowInsetsTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java7
-rw-r--r--libs/hwui/DeviceInfo.cpp7
-rw-r--r--libs/hwui/DeviceInfo.h7
-rw-r--r--libs/hwui/JankTracker.cpp2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp4
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp125
-rw-r--r--libs/hwui/renderthread/RenderThread.h17
-rw-r--r--media/java/android/media/IMediaRoute2Provider.aidl2
-rw-r--r--media/java/android/media/IMediaRouter2Manager.aidl2
-rw-r--r--media/java/android/media/IMediaRouterService.aidl5
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java8
-rw-r--r--media/java/android/media/MediaRoute2Info.java137
-rw-r--r--media/java/android/media/MediaRoute2ProviderInfo.java14
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java27
-rw-r--r--media/java/android/media/MediaRouter2.java215
-rw-r--r--media/java/android/media/MediaRouter2Manager.java39
-rw-r--r--media/java/android/media/RouteDiscoveryRequest.aidl19
-rw-r--r--media/java/android/media/RouteDiscoveryRequest.java200
-rw-r--r--media/java/android/media/RouteSessionInfo.java48
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java102
-rw-r--r--media/java/android/media/tv/tuner/FilterConfiguration.java329
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java125
-rw-r--r--media/java/android/media/tv/tuner/TunerConstants.java35
-rw-r--r--media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java37
-rw-r--r--media/java/android/media/tv/tuner/filter/AvSettings.java36
-rw-r--r--media/java/android/media/tv/tuner/filter/DownloadSettings.java32
-rw-r--r--media/java/android/media/tv/tuner/filter/FilterConfiguration.java44
-rw-r--r--media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java40
-rw-r--r--media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java36
-rw-r--r--media/java/android/media/tv/tuner/filter/PesSettings.java79
-rw-r--r--media/java/android/media/tv/tuner/filter/RecordSettings.java33
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettings.java31
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java33
-rw-r--r--media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java30
-rw-r--r--media/java/android/media/tv/tuner/filter/Settings.java37
-rw-r--r--media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java38
-rw-r--r--media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java75
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendCallback.java2
-rw-r--r--media/java/android/media/tv/tuner/frontend/ScanMessage.java (renamed from media/java/android/media/tv/tuner/ScanMessage.java)69
-rw-r--r--media/jni/android_media_tv_Tuner.cpp45
-rw-r--r--media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java36
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java156
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java91
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java87
-rw-r--r--mms/java/android/telephony/MmsManager.java29
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java24
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java6
-rw-r--r--packages/SystemUI/res/layout/people_strip.xml222
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java131
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt163
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java178
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java333
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java112
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java3
-rw-r--r--packages/Tethering/Android.bp2
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java101
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java218
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java50
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java2
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java106
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java204
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java12
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java230
-rw-r--r--rs/java/android/renderscript/RenderScript.java33
-rw-r--r--rs/jni/Android.mk1
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp58
-rw-r--r--services/Android.bp2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java70
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java2
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java88
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java26
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java58
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java15
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java96
-rw-r--r--services/core/java/com/android/server/compat/OverrideValidatorImpl.java94
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java67
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java27
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java31
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/integrity/IntegrityFileManager.java3
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleIndexRange.java50
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleIndexingController.java62
-rw-r--r--services/core/java/com/android/server/location/LocationRequestStatistics.java125
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java15
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java33
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java75
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java9
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java179
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java50
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecordImpl.java143
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java280
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java161
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java24
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java6
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java10
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java69
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java2
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java67
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java109
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java2
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java9
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java353
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimationRunner.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java47
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java5
-rw-r--r--services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java97
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java24
-rw-r--r--services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java74
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java99
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java291
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java383
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java180
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java168
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/power/NotifierTest.java287
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java39
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java153
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java34
-rw-r--r--telephony/common/com/android/internal/telephony/util/TelephonyUtils.java (renamed from telephony/java/com/android/internal/telephony/util/TelephonyUtils.java)0
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java8
-rw-r--r--telephony/java/android/telephony/CellIdentity.java1
-rw-r--r--telephony/java/android/telephony/CellLocation.java7
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java12
-rw-r--r--telephony/java/android/telephony/NetworkScan.java7
-rw-r--r--telephony/java/android/telephony/ServiceState.java23
-rw-r--r--telephony/java/android/telephony/SmsManager.java46
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java511
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java44
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java7
-rw-r--r--telephony/java/android/telephony/euicc/EuiccCardManager.java7
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java8
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java8
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java7
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java14
-rw-r--r--telephony/java/android/telephony/ims/RcsControllerCall.java9
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java8
-rw-r--r--telephony/java/com/android/telephony/Rlog.java154
-rw-r--r--tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java5
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java28
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java35
-rw-r--r--tests/net/java/android/net/NetworkStatsTest.java334
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsObserversTest.java16
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java110
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp5
-rw-r--r--wifi/Android.bp4
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java10
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java36
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java43
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java5
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java57
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java14
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java1
354 files changed, 11708 insertions, 4380 deletions
diff --git a/Android.bp b/Android.bp
index bba6185739fd..477f0272efa0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -262,12 +262,13 @@ filegroup {
name: "framework-updatable-sources",
srcs: [
":framework-appsearch-sources",
- ":framework-sdkext-sources",
+ ":framework-sdkextensions-sources",
":framework-statsd-sources",
":framework-tethering-srcs",
":updatable-media-srcs",
":framework-mediaprovider-sources",
":framework-wifi-updatable-sources",
+ ":ike-srcs",
]
}
@@ -432,6 +433,7 @@ java_library {
// TODO(b/146167933): Use framework-statsd-stubs
"framework-statsd",
"framework-wifi-stubs",
+ "ike-stubs",
],
installable: true,
javac_shard_size: 150,
@@ -481,11 +483,12 @@ java_library {
"updatable_media_stubs",
"framework_mediaprovider_stubs",
"framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
- "framework-sdkext-stubs-systemapi",
+ "framework-sdkextensions-stubs-systemapi",
// TODO(b/146167933): Use framework-statsd-stubs instead.
"framework-statsd",
// TODO(b/140299412): should be framework-wifi-stubs
"framework-wifi",
+ "ike-stubs",
// TODO(jiyong): add more stubs for APEXes here
],
sdk_version: "core_platform",
@@ -1134,6 +1137,7 @@ filegroup {
srcs: [
":framework-annotations",
"core/java/android/net/InterfaceConfiguration.java",
+ "core/java/android/os/BasicShellCommandHandler.java",
"core/java/android/os/HandlerExecutor.java",
"core/java/android/util/BackupUtils.java",
"core/java/android/util/LocalLog.java",
diff --git a/apex/blobstore/OWNERS b/apex/blobstore/OWNERS
new file mode 100644
index 000000000000..8e04399196e2
--- /dev/null
+++ b/apex/blobstore/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+
+sudheersai@google.com
+yamasani@google.com
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
new file mode 100644
index 000000000000..4dc0c49380c8
--- /dev/null
+++ b/apex/blobstore/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsBlobStoreTestCases"
+ }
+ ]
+} \ No newline at end of file
diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java
index c3dd3fe4451c..d059c670ccb6 100644
--- a/apex/media/framework/java/android/media/MediaController2.java
+++ b/apex/media/framework/java/android/media/MediaController2.java
@@ -141,6 +141,9 @@ public class MediaController2 implements AutoCloseable {
// Note: unbindService() throws IllegalArgumentException when it's called twice.
return;
}
+ if (DEBUG) {
+ Log.d(TAG, "closing " + this);
+ }
mClosed = true;
if (mServiceConnection != null) {
// Note: This should be called even when the bindService() has returned false.
diff --git a/apex/sdkext/Android.bp b/apex/sdkextensions/Android.bp
index f62f167cdcfa..4c5c2b2cfd4f 100644
--- a/apex/sdkext/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -18,21 +18,26 @@ package {
apex {
name: "com.android.sdkext",
- manifest: "manifest.json",
+ defaults: [ "com.android.sdkext-defaults" ],
binaries: [ "derive_sdk" ],
- java_libs: [ "framework-sdkext" ],
+ prebuilts: [ "cur_sdkinfo" ],
+ manifest: "manifest.json",
+}
+
+apex_defaults {
+ name: "com.android.sdkext-defaults",
+ java_libs: [ "framework-sdkextensions" ],
prebuilts: [
- "com.android.sdkext.ldconfig",
- "cur_sdkinfo",
- "derive_sdk.rc",
+ "com.android.sdkext.ldconfig",
+ "derive_sdk.rc",
],
key: "com.android.sdkext.key",
certificate: ":com.android.sdkext.certificate",
}
sdk {
- name: "sdkext-sdk",
- java_header_libs: [ "framework-sdkext-stubs-systemapi" ],
+ name: "sdkextensions-sdk",
+ java_header_libs: [ "framework-sdkextensions-stubs-systemapi" ],
}
apex_key {
diff --git a/apex/sdkext/OWNERS b/apex/sdkextensions/OWNERS
index feb274262bef..feb274262bef 100644
--- a/apex/sdkext/OWNERS
+++ b/apex/sdkextensions/OWNERS
diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkextensions/TEST_MAPPING
index 91947f39980a..7e7762337afc 100644
--- a/apex/sdkext/TEST_MAPPING
+++ b/apex/sdkextensions/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsSdkExtTestCases"
+ },
+ {
+ "name": "apiextensions_e2e_tests"
}
]
}
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkextensions/com.android.sdkext.avbpubkey
index 8f47741ed3b8..8f47741ed3b8 100644
--- a/apex/sdkext/com.android.sdkext.avbpubkey
+++ b/apex/sdkextensions/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkextensions/com.android.sdkext.pem
index 816460183aa3..816460183aa3 100644
--- a/apex/sdkext/com.android.sdkext.pem
+++ b/apex/sdkextensions/com.android.sdkext.pem
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkextensions/com.android.sdkext.pk8
index ccc0bf438cd1..ccc0bf438cd1 100644
--- a/apex/sdkext/com.android.sdkext.pk8
+++ b/apex/sdkextensions/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkextensions/com.android.sdkext.x509.pem
index 45d2ade354d4..45d2ade354d4 100644
--- a/apex/sdkext/com.android.sdkext.x509.pem
+++ b/apex/sdkextensions/com.android.sdkext.x509.pem
diff --git a/apex/sdkext/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp
index c4e3c296f210..cf49902d9978 100644
--- a/apex/sdkext/derive_sdk/Android.bp
+++ b/apex/sdkextensions/derive_sdk/Android.bp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_binary {
- name: "derive_sdk",
+cc_defaults {
+ name: "derive_sdk-defaults",
srcs: [
"derive_sdk.cpp",
"sdk.proto",
@@ -30,6 +30,24 @@ cc_binary {
],
}
+cc_binary {
+ name: "derive_sdk",
+ defaults: [ "derive_sdk-defaults" ],
+ apex_available: [ "com.android.sdkext" ],
+ visibility: [ "//frameworks/base/apex/sdkextensions" ]
+}
+
+// Work around testing using a 64-bit test suite on 32-bit test device by
+// using a prefer32 version of derive_sdk in testing.
+cc_binary {
+ name: "derive_sdk_prefer32",
+ defaults: [ "derive_sdk-defaults" ],
+ compile_multilib: "prefer32",
+ stem: "derive_sdk",
+ apex_available: [ "test_com.android.sdkext" ],
+ visibility: [ "//frameworks/base/apex/sdkextensions/testing" ]
+}
+
prebuilt_etc {
name: "derive_sdk.rc",
src: "derive_sdk.rc",
diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
index 0a9711677015..6fb7ef43416e 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.cpp
+++ b/apex/sdkextensions/derive_sdk/derive_sdk.cpp
@@ -26,7 +26,7 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include "frameworks/base/apex/sdkext/derive_sdk/sdk.pb.h"
+#include "frameworks/base/apex/sdkextensions/derive_sdk/sdk.pb.h"
using com::android::sdkext::proto::SdkVersion;
diff --git a/apex/sdkext/derive_sdk/derive_sdk.rc b/apex/sdkextensions/derive_sdk/derive_sdk.rc
index 1b667949eeaa..1b667949eeaa 100644
--- a/apex/sdkext/derive_sdk/derive_sdk.rc
+++ b/apex/sdkextensions/derive_sdk/derive_sdk.rc
diff --git a/apex/sdkext/derive_sdk/sdk.proto b/apex/sdkextensions/derive_sdk/sdk.proto
index d15b93552ff4..d15b93552ff4 100644
--- a/apex/sdkext/derive_sdk/sdk.proto
+++ b/apex/sdkextensions/derive_sdk/sdk.proto
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index a50dc3d4f349..5504f4e5dd8e 100644
--- a/apex/sdkext/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -17,55 +17,58 @@ package {
}
filegroup {
- name: "framework-sdkext-sources",
+ name: "framework-sdkextensions-sources",
srcs: [
"java/**/*.java",
],
path: "java",
- visibility: [ "//frameworks/base:__pkg__" ] // For the "global" stubs.
+ visibility: [ "//frameworks/base" ] // For the "global" stubs.
}
java_library {
- name: "framework-sdkext",
- srcs: [ ":framework-sdkext-sources" ],
+ name: "framework-sdkextensions",
+ srcs: [ ":framework-sdkextensions-sources" ],
sdk_version: "system_current",
libs: [ "framework-annotations-lib" ],
permitted_packages: [ "android.os.ext" ],
installable: true,
- visibility: [ "//frameworks/base/apex/sdkext:__pkg__" ],
+ visibility: [
+ "//frameworks/base/apex/sdkextensions",
+ "//frameworks/base/apex/sdkextensions/testing",
+ ],
}
droidstubs {
- name: "framework-sdkext-droidstubs-publicapi",
+ name: "framework-sdkextensions-droidstubs-publicapi",
defaults: [
- "framework-sdkext-stubs-defaults",
+ "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-publicapi",
]
}
droidstubs {
- name: "framework-sdkext-droidstubs-systemapi",
+ name: "framework-sdkextensions-droidstubs-systemapi",
defaults: [
- "framework-sdkext-stubs-defaults",
+ "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-systemapi",
]
}
stubs_defaults {
- name: "framework-sdkext-stubs-defaults",
+ name: "framework-sdkextensions-stubs-defaults",
srcs: [
- ":framework-sdkext-sources",
+ ":framework-sdkextensions-sources",
":framework-annotations",
],
sdk_version: "system_current",
}
java_library {
- name: "framework-sdkext-stubs-systemapi",
- srcs: [":framework-sdkext-droidstubs-systemapi"],
+ name: "framework-sdkextensions-stubs-systemapi",
+ srcs: [":framework-sdkextensions-droidstubs-systemapi"],
sdk_version: "system_current",
visibility: [
- "//frameworks/base:__pkg__", // Framework
- "//frameworks/base/apex/sdkext:__pkg__", // sdkext SDK
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
]
}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
index a8a7effa9b6c..a8a7effa9b6c 100644
--- a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
+++ b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkextensions/framework/java/android/os/ext/package.html
index 34c1697c01fd..34c1697c01fd 100644
--- a/apex/sdkext/framework/java/android/os/ext/package.html
+++ b/apex/sdkextensions/framework/java/android/os/ext/package.html
diff --git a/apex/sdkext/gen_sdkinfo.py b/apex/sdkextensions/gen_sdkinfo.py
index 5af478ba7fe6..5af478ba7fe6 100644
--- a/apex/sdkext/gen_sdkinfo.py
+++ b/apex/sdkextensions/gen_sdkinfo.py
diff --git a/apex/sdkext/ld.config.txt b/apex/sdkextensions/ld.config.txt
index b4470685f4fc..dcc69b892760 100644
--- a/apex/sdkext/ld.config.txt
+++ b/apex/sdkextensions/ld.config.txt
@@ -1,10 +1,10 @@
# Copyright (C) 2019 The Android Open Source Project
#
-# Bionic loader config file for the sdkext apex.
+# Bionic loader config file for the sdkextensions apex.
-dir.sdkext = /apex/com.android.sdkext/bin/
+dir.sdkextensions = /apex/com.android.sdkext/bin/
-[sdkext]
+[sdkextensions]
additional.namespaces = platform
namespace.default.isolated = true
diff --git a/apex/sdkext/manifest.json b/apex/sdkextensions/manifest.json
index 048f5c4f177b..048f5c4f177b 100644
--- a/apex/sdkext/manifest.json
+++ b/apex/sdkextensions/manifest.json
diff --git a/apex/sdkext/sdk.proto b/apex/sdkextensions/sdk.proto
index d15b93552ff4..d15b93552ff4 100644
--- a/apex/sdkext/sdk.proto
+++ b/apex/sdkextensions/sdk.proto
diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp
new file mode 100644
index 000000000000..e6451cc29bc2
--- /dev/null
+++ b/apex/sdkextensions/testing/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+ name: "test_com.android.sdkext",
+ visibility: [ "//system/apex/tests" ],
+ defaults: ["com.android.sdkext-defaults"],
+ manifest: "test_manifest.json",
+ prebuilts: [ "sdkinfo_45" ],
+ file_contexts: ":com.android.sdkext-file_contexts",
+ installable: false, // Should never be installed on the systemimage
+ multilib: {
+ prefer32: {
+ binaries: ["derive_sdk_prefer32"],
+ },
+ },
+ // The automated test infra ends up building this apex for 64+32-bit and
+ // then installs it on a 32-bit-only device. Work around this weirdness
+ // by preferring 32-bit.
+ compile_multilib: "prefer32",
+}
+
+genrule {
+ name: "sdkinfo_45_src",
+ out: [ "sdkinfo.binarypb" ],
+ tools: [ "gen_sdkinfo" ],
+ cmd: "$(location) -v 45 -o $(out)",
+}
+
+prebuilt_etc {
+ name: "sdkinfo_45",
+ src: ":sdkinfo_45_src",
+ filename: "sdkinfo.binarypb",
+ installable: false,
+}
diff --git a/apex/sdkextensions/testing/test_manifest.json b/apex/sdkextensions/testing/test_manifest.json
new file mode 100644
index 000000000000..1b4a2b0c6e60
--- /dev/null
+++ b/apex/sdkextensions/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.sdkext",
+ "version": 2147483647
+}
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 055836777678..dec56345ec2f 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -85,4 +85,44 @@ interface IStatsManagerService {
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
+
+ /**
+ * Returns the most recently registered experiment IDs.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ long[] getRegisteredExperimentIds();
+
+ /**
+ * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getMetadata(in String packageName);
+
+ /**
+ * Fetches data for the specified configuration key. Returns a byte array representing proto
+ * wire-encoded of ConfigMetricsReportList.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ byte[] getData(in long key, in String packageName);
+
+ /**
+ * Sets a configuration with the specified config id and subscribes to updates for this
+ * configuration id. Broadcasts will be sent if this configuration needs to be collected.
+ * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
+ * registered in a separate function.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void addConfiguration(in long configId, in byte[] config, in String packageName);
+
+ /**
+ * Removes the configuration with the matching config id. No-op if this config id does not
+ * exist.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void removeConfiguration(in long configId, in String packageName);
} \ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 935843921feb..c409f516de1b 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -89,24 +89,24 @@ interface IStatsd {
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getData(in long key, in String packageName);
+ byte[] getData(in long key, int callingUid);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getMetadata(in String packageName);
+ byte[] getMetadata();
/**
- * Sets a configuration with the specified config key and subscribes to updates for this
+ * Sets a configuration with the specified config id and subscribes to updates for this
* configuration key. Broadcasts will be sent if this configuration needs to be collected.
* The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
* registered in a separate function.
*
* Requires Manifest.permission.DUMP.
*/
- void addConfiguration(in long configKey, in byte[] config, in String packageName);
+ void addConfiguration(in long configId, in byte[] config, in int callingUid);
/**
* Registers the given pending intent for this config key. This intent is invoked when the
@@ -143,12 +143,12 @@ interface IStatsd {
void removeActiveConfigsChangedOperation(int callingUid);
/**
- * Removes the configuration with the matching config key. No-op if this config key does not
+ * Removes the configuration with the matching config id. No-op if this config id does not
* exist.
*
* Requires Manifest.permission.DUMP.
*/
- void removeConfiguration(in long configKey, in String packageName);
+ void removeConfiguration(in long configId, in int callingUid);
/**
* Set the PendingIntentRef to be used when broadcasting subscriber
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 1d03e3b702c4..b27d0f7699fc 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.stats;
import static com.android.server.stats.StatsCompanion.PendingIntentRef;
import android.Manifest;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
@@ -245,20 +246,127 @@ public class StatsManagerService extends IStatsManagerService.Stub {
}
}
+ @Override
+ public long[] getRegisteredExperimentIds() throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getRegisteredExperimentIds();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to registerExperimentIds");
+ }
+
+ @Override
+ public byte[] getMetadata(String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getMetadata();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getMetadata with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getMetadata");
+ }
+
+ @Override
+ public byte[] getData(long key, String packageName) throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ return statsd.getData(key, callingUid);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to getData with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to getData");
+ }
+
+ @Override
+ public void addConfiguration(long configId, byte[] config, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.addConfiguration(configId, config, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to addConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to addConfig");
+ }
+
+ @Override
+ public void removeConfiguration(long configId, String packageName)
+ throws IllegalStateException {
+ enforceDumpAndUsageStatsPermission(packageName);
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IStatsd statsd = waitForStatsd();
+ if (statsd != null) {
+ statsd.removeConfiguration(configId, callingUid);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to removeConfiguration with statsd");
+ throw new IllegalStateException(e.getMessage(), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ throw new IllegalStateException("Failed to connect to statsd to removeConfig");
+ }
+
void setStatsCompanionService(StatsCompanionService statsCompanionService) {
mStatsCompanionService = statsCompanionService;
}
- private void enforceDumpAndUsageStatsPermission(String packageName) {
+ /**
+ * Checks that the caller has both DUMP and PACKAGE_USAGE_STATS permissions. Also checks that
+ * the caller has USAGE_STATS_PERMISSION_OPS for the specified packageName if it is not null.
+ *
+ * @param packageName The packageName to check USAGE_STATS_PERMISSION_OPS.
+ */
+ private void enforceDumpAndUsageStatsPermission(@Nullable String packageName) {
int callingUid = Binder.getCallingUid();
int callingPid = Binder.getCallingPid();
if (callingPid == Process.myPid()) {
return;
}
+
mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, null);
+ if (packageName == null) {
+ return;
+ }
AppOpsManager appOpsManager = (AppOpsManager) mContext
.getSystemService(Context.APP_OPS_SERVICE);
switch (appOpsManager.noteOp(USAGE_STATS_PERMISSION_OPS,
diff --git a/api/current.txt b/api/current.txt
index 51641f23a49e..b673df0b5c90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9504,6 +9504,7 @@ package android.content {
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Nullable public final String getCallingFeatureId();
method @Nullable public final String getCallingPackage();
+ method @Nullable public final String getCallingPackageUnchecked();
method @Nullable public final android.content.Context getContext();
method @Nullable public final android.content.pm.PathPermission[] getPathPermissions();
method @Nullable public final String getReadPermission();
@@ -9513,6 +9514,7 @@ package android.content {
method @Nullable public abstract android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues);
method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable android.os.Bundle);
method protected boolean isTemporary();
+ method public void onCallingPackageChanged();
method public void onConfigurationChanged(android.content.res.Configuration);
method public abstract boolean onCreate();
method public void onLowMemory();
@@ -9627,13 +9629,13 @@ package android.content {
ctor public ContentProviderResult(@NonNull android.net.Uri);
ctor public ContentProviderResult(int);
ctor public ContentProviderResult(@NonNull android.os.Bundle);
- ctor public ContentProviderResult(@NonNull Exception);
+ ctor public ContentProviderResult(@NonNull Throwable);
ctor public ContentProviderResult(android.os.Parcel);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR;
field @Nullable public final Integer count;
- field @Nullable public final Exception exception;
+ field @Nullable public final Throwable exception;
field @Nullable public final android.os.Bundle extras;
field @Nullable public final android.net.Uri uri;
}
@@ -9998,6 +10000,7 @@ package android.content {
field public static final String MEDIA_ROUTER_SERVICE = "media_router";
field public static final String MEDIA_SESSION_SERVICE = "media_session";
field public static final String MIDI_SERVICE = "midi";
+ field public static final String MMS_SERVICE = "mms";
field public static final int MODE_APPEND = 32768; // 0x8000
field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4
@@ -13323,6 +13326,7 @@ package android.database.sqlite {
method @Deprecated public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String[], String, String);
method public int delete(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable String, @Nullable String[]);
method @Nullable public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+ method @Nullable public java.util.Collection<java.util.regex.Pattern> getProjectionGreylist();
method @Nullable public java.util.Map<java.lang.String,java.lang.String> getProjectionMap();
method @Nullable public String getTables();
method public long insert(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues);
@@ -13335,6 +13339,7 @@ package android.database.sqlite {
method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
method public void setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method public void setDistinct(boolean);
+ method public void setProjectionGreylist(@Nullable java.util.Collection<java.util.regex.Pattern>);
method public void setProjectionMap(@Nullable java.util.Map<java.lang.String,java.lang.String>);
method public void setStrict(boolean);
method public void setStrictColumns(boolean);
@@ -25781,8 +25786,8 @@ package android.media {
method @Nullable public android.graphics.Bitmap getImageAtIndex(int);
method @Nullable public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
method @Nullable public android.graphics.Bitmap getPrimaryImage();
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
- method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int);
+ method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public void release();
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -28683,6 +28688,8 @@ package android.media.tv {
method public int getVideoWidth();
method public boolean isAudioDescription();
method public boolean isEncrypted();
+ method public boolean isHardOfHearing();
+ method public boolean isSpokenSubtitle();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR;
field public static final int TYPE_AUDIO = 0; // 0x0
@@ -28699,7 +28706,9 @@ package android.media.tv {
method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence);
method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean);
method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
+ method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean);
method public android.media.tv.TvTrackInfo.Builder setLanguage(String);
+ method @NonNull public android.media.tv.TvTrackInfo.Builder setSpokenSubtitle(boolean);
method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
@@ -29011,6 +29020,37 @@ package android.net {
field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
}
+ public class ConnectivityDiagnosticsManager {
+ method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+ }
+
+ public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+ method public void onConnectivityReport(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+ method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+ method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+ }
+
+ public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ field @NonNull public final android.os.PersistableBundle additionalInfo;
+ field @NonNull public final android.net.LinkProperties linkProperties;
+ field @NonNull public final android.net.Network network;
+ field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
+ field public final long reportTimestamp;
+ }
+
+ public static class ConnectivityDiagnosticsManager.DataStallReport {
+ ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle);
+ field public final int detectionMethod;
+ field @NonNull public final android.net.Network network;
+ field public final long reportTimestamp;
+ field @NonNull public final android.os.PersistableBundle stallDetails;
+ }
+
public class ConnectivityManager {
method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
@@ -30280,6 +30320,7 @@ package android.net.wifi {
@Deprecated public static class WifiConfiguration.AuthAlgorithm {
field @Deprecated public static final int LEAP = 2; // 0x2
field @Deprecated public static final int OPEN = 0; // 0x0
+ field @Deprecated public static final int SAE = 3; // 0x3
field @Deprecated public static final int SHARED = 1; // 0x1
field @Deprecated public static final String[] strings;
field @Deprecated public static final String varName = "auth_alg";
@@ -35682,7 +35723,9 @@ package android.os {
method public int describeContents();
method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String);
method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle);
+ method @NonNull public static android.os.PersistableBundle readFromStream(@NonNull java.io.InputStream) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException;
field @NonNull public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR;
field public static final android.os.PersistableBundle EMPTY;
}
@@ -36350,15 +36393,22 @@ package android.os.storage {
method public boolean isObbMounted(String);
method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener);
method @NonNull public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
+ method public void registerStorageVolumeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.storage.StorageManager.StorageVolumeCallback);
method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(String, boolean, android.os.storage.OnObbStateChangeListener);
+ method public void unregisterStorageVolumeCallback(@NonNull android.os.storage.StorageManager.StorageVolumeCallback);
field public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
field public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
field public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
field public static final java.util.UUID UUID_DEFAULT;
}
+ public static class StorageManager.StorageVolumeCallback {
+ ctor public StorageManager.StorageVolumeCallback();
+ method public void onStateChanged(@NonNull android.os.storage.StorageVolume);
+ }
+
public final class StorageVolume implements android.os.Parcelable {
method @Deprecated @Nullable public android.content.Intent createAccessIntent(String);
method @NonNull public android.content.Intent createOpenDocumentTreeIntent();
@@ -45465,6 +45515,11 @@ package android.telephony {
method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
}
+ public final class MmsManager {
+ method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
+ method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
+ }
+
@Deprecated public class NeighboringCellInfo implements android.os.Parcelable {
ctor @Deprecated public NeighboringCellInfo();
ctor @Deprecated public NeighboringCellInfo(int, int);
@@ -45661,6 +45716,7 @@ package android.telephony {
method public String getOperatorNumeric();
method public boolean getRoaming();
method public int getState();
+ method public boolean isSearching();
method public void setIsManualSelection(boolean);
method public void setOperatorName(String, String, String);
method public void setRoaming(boolean);
@@ -45701,8 +45757,8 @@ package android.telephony {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
- method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
- method @Nullable public android.os.Bundle getCarrierConfigValues();
+ method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+ method @NonNull public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
@@ -45711,7 +45767,7 @@ package android.telephony {
method public int getSubscriptionId();
method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
- method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+ method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
@@ -45919,6 +45975,7 @@ package android.telephony {
public class SubscriptionManager {
method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+ method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
diff --git a/api/system-current.txt b/api/system-current.txt
index 41ded16bff08..41e55902cb48 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -567,6 +567,7 @@ package android.app {
}
public class DownloadManager {
+ method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public void onMediaStoreDownloadsDeleted(@NonNull android.util.LongSparseArray<java.lang.String>);
field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
}
@@ -677,6 +678,7 @@ package android.app {
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
@@ -799,6 +801,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isOrganizationOwnedDeviceWithManagedProfile();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
@@ -1652,11 +1655,17 @@ package android.content {
method @NonNull public final android.os.UserHandle getSendingUser();
}
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
+ method public int checkUriPermission(@NonNull android.net.Uri, int, int);
+ }
+
public class ContentProviderClient implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
}
public abstract class ContentResolver {
+ method @NonNull public static android.net.Uri decodeFromFile(@NonNull java.io.File);
+ method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri);
method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri);
method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
}
@@ -1697,6 +1706,7 @@ package android.content {
field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
field public static final String TETHERING_SERVICE = "tethering";
field public static final String VR_SERVICE = "vrmanager";
+ field public static final String WIFI_COND_SERVICE = "wificond";
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
}
@@ -3578,9 +3588,17 @@ package android.hardware.usb {
}
public class UsbManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
+ field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
+ field public static final long FUNCTION_NONE = 0L; // 0x0L
+ field public static final long FUNCTION_RNDIS = 32L; // 0x20L
+ field public static final String USB_CONFIGURED = "configured";
+ field public static final String USB_CONNECTED = "connected";
+ field public static final String USB_FUNCTION_RNDIS = "rndis";
}
public final class UsbPort {
@@ -4897,6 +4915,33 @@ package android.net {
field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
}
+ public final class NetworkStats implements android.os.Parcelable {
+ ctor public NetworkStats(long, int);
+ method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats);
+ method @NonNull public android.net.NetworkStats addValues(@NonNull android.net.NetworkStats.Entry);
+ method public int describeContents();
+ method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
+ field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
+ field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
+ field @Nullable public static final String IFACE_ALL;
+ field public static final String IFACE_VT = "vt_data0";
+ field public static final int METERED_NO = 0; // 0x0
+ field public static final int METERED_YES = 1; // 0x1
+ field public static final int ROAMING_NO = 0; // 0x0
+ field public static final int ROAMING_YES = 1; // 0x1
+ field public static final int SET_DEFAULT = 0; // 0x0
+ field public static final int SET_FOREGROUND = 1; // 0x1
+ field public static final int TAG_NONE = 0; // 0x0
+ field public static final int UID_ALL = -1; // 0xffffffff
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
+ public static class NetworkStats.Entry {
+ ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
+ }
+
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
method public int getType();
@@ -5927,6 +5972,7 @@ package android.net.wifi {
public class WifiManager {
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -6003,6 +6049,7 @@ package android.net.wifi {
field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
+ field public static final String EXTRA_WIFI_AP_FAILURE_REASON = "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
@@ -6291,6 +6338,10 @@ package android.net.wifi.hotspot2 {
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
}
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ method public boolean isAutoJoinEnabled();
+ }
+
public abstract class ProvisioningCallback {
ctor public ProvisioningCallback();
method public abstract void onProvisioningComplete();
@@ -6957,6 +7008,10 @@ package android.os {
method public boolean hasSingleFileDescriptor();
}
+ public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
+ method @NonNull public static android.os.ParcelFileDescriptor wrap(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.Handler, @NonNull android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
+ }
+
public final class PowerManager {
method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
@@ -7065,7 +7120,22 @@ package android.os {
}
public class TelephonyServiceManager {
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getCarrierConfigServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccCardControllerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccControllerService();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getIccPhoneBookServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getNetworkPolicyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getOpportunisticNetworkServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPackageManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPermissionManagerServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPhoneSubServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSmsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSubscriptionServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyImsServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRcsMessageServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyRegistryServiceRegisterer();
method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getTelephonyServiceRegisterer();
+ method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getWindowServiceRegisterer();
}
public static class TelephonyServiceManager.ServiceNotFoundException extends java.lang.Exception {
@@ -7081,11 +7151,13 @@ package android.os {
public class UpdateEngine {
ctor public UpdateEngine();
+ method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]);
method public void applyPayload(String, long, long, String[]);
method public void applyPayload(@NonNull android.os.ParcelFileDescriptor, long, long, @NonNull String[]);
method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
method public boolean bind(android.os.UpdateEngineCallback);
method public void cancel();
+ method public int cleanupAppliedPayload();
method public void resetStatus();
method public void resume();
method public void suspend();
@@ -7093,14 +7165,21 @@ package android.os {
method public boolean verifyPayloadMetadata(String);
}
+ public static final class UpdateEngine.AllocateSpaceResult {
+ method public int errorCode();
+ method public long freeSpaceRequired();
+ }
+
public static final class UpdateEngine.ErrorCodeConstants {
ctor public UpdateEngine.ErrorCodeConstants();
+ field public static final int DEVICE_CORRUPTED = 61; // 0x3d
field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc
field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9
field public static final int ERROR = 1; // 0x1
field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4
field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7
field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8
+ field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c
field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
@@ -7336,6 +7415,10 @@ package android.os.storage {
field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
+ public final class StorageVolume implements android.os.Parcelable {
+ method @NonNull public String getId();
+ }
+
}
package android.permission {
@@ -7913,7 +7996,71 @@ package android.provider {
}
public static final class Telephony.SimInfo {
+ field public static final String ACCESS_RULES = "access_rules";
+ field public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = "access_rules_from_carrier_configs";
+ field public static final String CARD_ID = "card_id";
+ field public static final String CARRIER_ID = "carrier_id";
+ field public static final String CARRIER_NAME = "carrier_name";
+ field public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ field public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ field public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ field public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ field public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ field public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ field public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+ field public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ field public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ field public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ field public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ field public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ field public static final String COLOR = "color";
field @NonNull public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ field public static final String DATA_ROAMING = "data_roaming";
+ field public static final int DATA_ROAMING_DEFAULT = 0; // 0x0
+ field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
+ field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final String DISPLAY_NAME = "display_name";
+ field public static final String EHPLMNS = "ehplmns";
+ field public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ field public static final String GROUP_OWNER = "group_owner";
+ field public static final String GROUP_UUID = "group_uuid";
+ field public static final String HPLMNS = "hplmns";
+ field public static final String ICC_ID = "icc_id";
+ field public static final String IMSI = "imsi";
+ field public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ field public static final String IS_EMBEDDED = "is_embedded";
+ field public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ field public static final String IS_REMOVABLE = "is_removable";
+ field public static final String MCC = "mcc";
+ field public static final String MCC_STRING = "mcc_string";
+ field public static final String MNC = "mnc";
+ field public static final String MNC_STRING = "mnc_string";
+ field public static final String NAME_SOURCE = "name_source";
+ field public static final int NAME_SOURCE_CARRIER = 3; // 0x3
+ field public static final int NAME_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int NAME_SOURCE_SIM_PNN = 4; // 0x4
+ field public static final int NAME_SOURCE_SIM_SPN = 1; // 0x1
+ field public static final int NAME_SOURCE_USER_INPUT = 2; // 0x2
+ field public static final String NUMBER = "number";
+ field public static final String PROFILE_CLASS = "profile_class";
+ field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+ field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+ field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+ field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+ field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
+ field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
+ field public static final String SIM_SLOT_INDEX = "sim_id";
+ field public static final String SUBSCRIPTION_TYPE = "subscription_type";
+ field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+ field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
+ field public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ field public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ field public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ field public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ field public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ field public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ field public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
}
public static final class Telephony.Sms.Intents {
@@ -9180,30 +9327,37 @@ package android.telephony {
public abstract class CellIdentity implements android.os.Parcelable {
method @NonNull public abstract android.telephony.CellLocation asCellLocation();
+ method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo();
}
public final class CellIdentityCdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo();
}
public final class CellIdentityGsm extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo();
}
public final class CellIdentityLte extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo();
}
public final class CellIdentityNr extends android.telephony.CellIdentity {
method @NonNull public android.telephony.CellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo();
}
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo();
}
public final class CellIdentityWcdma extends android.telephony.CellIdentity {
method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
+ method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
}
public final class DataFailCause {
@@ -10381,6 +10535,20 @@ package android.telephony {
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
}
+ public final class WapPushManagerConnector {
+ ctor public WapPushManagerConnector(@NonNull android.content.Context);
+ method public boolean bindToWapPushManagerService();
+ method @Nullable public String getConnectedWapPushManagerServicePackage();
+ method public int processMessage(@NonNull String, @NonNull String, @NonNull android.content.Intent);
+ method public void unbindWapPushManagerService();
+ field public static final int RESULT_APP_QUERY_FAILED = 2; // 0x2
+ field public static final int RESULT_EXCEPTION_CAUGHT = 16; // 0x10
+ field public static final int RESULT_FURTHER_PROCESSING = 32768; // 0x8000
+ field public static final int RESULT_INVALID_RECEIVER_NAME = 8; // 0x8
+ field public static final int RESULT_MESSAGE_HANDLED = 1; // 0x1
+ field public static final int RESULT_SIGNATURE_NO_MATCH = 4; // 0x4
+ }
+
}
package android.telephony.cdma {
diff --git a/api/test-current.txt b/api/test-current.txt
index 99679428cefb..e64cbdb6eb10 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -437,6 +437,7 @@ package android.app {
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean);
}
public static final class StatusBarManager.DisableInfo {
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7b96ce92e307..118a508a9071 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -126,29 +126,28 @@ cc_defaults {
],
static_libs: [
- "libhealthhalutils",
- "libplatformprotos",
- ],
-
- shared_libs: [
"android.frameworks.stats@1.0",
- "android.hardware.health@2.0",
"android.hardware.power.stats@1.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"libbase",
- "libbinder",
"libcutils",
- "libgraphicsenv",
- "libhidlbase",
- "libincident",
+ "libhealthhalutils",
"liblog",
+ "libplatformprotos",
"libprotoutil",
- "libservices",
"libstatslog",
- "libstatsmetadata",
"libstatssocket",
"libsysutils",
+ ],
+ shared_libs: [
+ "android.hardware.health@2.0",
+ "libbinder",
+ "libgraphicsenv",
+ "libhidlbase",
+ "libincident",
+ "libservices",
+ "libstatsmetadata",
"libtimestats_proto",
"libutils",
],
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 5ff0f97865b8..1ca19c3417c2 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1135,12 +1135,11 @@ void StatsService::OnLogEvent(LogEvent* event) {
}
}
-Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
- ConfigKey configKey(ipc->getCallingUid(), key);
+ VLOG("StatsService::getData with Uid %i", callingUid);
+ ConfigKey configKey(callingUid, key);
// The dump latency does not matter here since we do not include the current bucket, we do not
// need to pull any new data anyhow.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
@@ -1148,22 +1147,18 @@ Status StatsService::getData(int64_t key, const String16& packageName, vector<ui
return Status::ok();
}
-Status StatsService::getMetadata(const String16& packageName, vector<uint8_t>* output) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::getMetadata(vector<uint8_t>* output) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
- ipc->getCallingUid());
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
return Status::ok();
}
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
- const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+ const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
+ if (addConfigurationChecked(callingUid, key, config)) {
return Status::ok();
} else {
ALOGE("Could not parse malformatted StatsdConfig");
@@ -1228,13 +1223,11 @@ Status StatsService::removeActiveConfigsChangedOperation(const int32_t callingUi
return Status::ok();
}
-Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
- ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
- IPCThreadState* ipc = IPCThreadState::self();
- ConfigKey configKey(ipc->getCallingUid(), key);
+ ConfigKey configKey(callingUid, key);
mConfigManager->RemoveConfig(configKey);
- SubscriberReporter::getInstance().removeConfig(configKey);
return Status::ok();
}
@@ -1477,17 +1470,7 @@ Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackType
Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
-
- // Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
- }
- if (!checkCallingPermission(String16(kPermissionUsage))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
- }
+ ENFORCE_UID(AID_SYSTEM);
// TODO: add verifier permission
// Read the latest train info
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 0565f3ce2484..c9a9072ecb92 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -99,15 +99,14 @@ public:
* Binder call for clients to request data for this configuration key.
*/
virtual Status getData(int64_t key,
- const String16& packageName,
+ const int32_t callingUid,
vector<uint8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
- virtual Status getMetadata(const String16& packageName,
- vector<uint8_t>* output) override;
+ virtual Status getMetadata(vector<uint8_t>* output) override;
/**
@@ -116,7 +115,7 @@ public:
*/
virtual Status addConfiguration(int64_t key,
const vector<uint8_t>& config,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
@@ -146,7 +145,7 @@ public:
* Binder call to allow clients to remove the specified configuration.
*/
virtual Status removeConfiguration(int64_t key,
- const String16& packageName) override;
+ const int32_t callingUid) override;
/**
* Binder call to associate the given config's subscriberId with the given pendingIntentRef.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 55d73c1ae342..972adf7d4d05 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -189,25 +189,11 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
// Remove from map
uidIt->second.erase(key);
- // No more configs for this uid, lets remove the active configs callback.
- if (uidIt->second.empty()) {
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
- }
- }
-
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
}
- auto itReceiver = mConfigReceivers.find(key);
- if (itReceiver != mConfigReceivers.end()) {
- // Remove from map
- mConfigReceivers.erase(itReceiver);
- }
-
// Remove from disk. There can still be a lingering file on disk so we check
// whether or not the config was on memory.
remove_saved_configs(key);
@@ -238,12 +224,6 @@ void ConfigManager::RemoveConfigs(int uid) {
// Remove from map
remove_saved_configs(*it);
removed.push_back(*it);
- mConfigReceivers.erase(*it);
- }
-
- auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
- if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
- mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
}
mConfigs.erase(uidIt);
@@ -277,8 +257,6 @@ void ConfigManager::RemoveAllConfigs() {
uidIt = mConfigs.erase(uidIt);
}
- mConfigReceivers.clear();
- mActiveConfigsChangedReceivers.clear();
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 35c6d373418e..e85b97514242 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -207,10 +207,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
&linkedConditionDimensionKey);
if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
trueConditionDimensions.end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(
- currentUnSlicedPartCondition, eventTime);
- }
+ whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
}
}
} else {
@@ -222,15 +219,11 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
&linkedConditionDimensionKey);
if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
dimensionsChangedToTrue->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(true, eventTime);
- }
+ whatIt.second->onConditionChanged(true, eventTime);
}
if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
dimensionsChangedToFalse->end()) {
- for (auto& condIt : whatIt.second) {
- condIt.second->onConditionChanged(false, eventTime);
- }
+ whatIt.second->onConditionChanged(false, eventTime);
}
}
}
@@ -247,9 +240,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overa
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
- }
+ whatIt.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
}
}
@@ -283,18 +274,14 @@ void DurationMetricProducer::onActiveStateChangedLocked(const int64_t& eventTime
}
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
} else if (mIsActive) {
flushIfNeededLocked(eventTimeNs);
onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
} else { // mConditionSliced == true && !mIsActive
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(mIsActive, eventTimeNs);
- }
+ whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
}
}
}
@@ -310,9 +297,7 @@ void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
flushIfNeededLocked(eventTime);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->onConditionChanged(conditionMet, eventTime);
- }
+ whatIt.second->onConditionChanged(conditionMet, eventTime);
}
}
@@ -425,19 +410,11 @@ void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs
const int64_t& nextBucketStartTimeNs) {
for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
- for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
- if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s", whatIt->first.toString().c_str(),
- it->first.toString().c_str());
- it = whatIt->second.erase(it);
- } else {
- ++it;
- }
- }
- if (whatIt->second.empty()) {
+ if (whatIt->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
+ VLOG("erase bucket for key %s", whatIt->first.toString().c_str());
whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
} else {
- whatIt++;
+ ++whatIt;
}
}
StatsdStats::getInstance().noteBucketCount(mMetricId);
@@ -453,35 +430,15 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
(unsigned long)mCurrentSlicedDurationTrackerMap.size());
if (verbose) {
for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (const auto& slice : whatIt.second) {
- fprintf(out, "\t(what)%s\t(states)%s\n", whatIt.first.toString().c_str(),
- slice.first.toString().c_str());
- slice.second->dumpStates(out, verbose);
- }
+ fprintf(out, "\t(what)%s\n", whatIt.first.toString().c_str());
+ whatIt.second->dumpStates(out, verbose);
}
}
}
bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- auto stateIt = whatIt->second.find(newKey.getStateValuesKey());
- if (stateIt != whatIt->second.end()) {
- return false;
- }
- if (whatIt->second.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
- size_t newTupleCount = whatIt->second.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionInConditionSize(
- 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 state values key %s",
- (long long)mMetricId, newKey.getStateValuesKey().toString().c_str());
- StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
- return true;
- }
- }
- } else {
+ if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
// 1. Report the tuple count if the tuple count > soft limit
if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
@@ -503,24 +460,16 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
const ConditionKey& conditionKeys,
bool condition, const LogEvent& event) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
- const auto& stateKey = eventKey.getStateValuesKey();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- } else {
- if (whatIt->second.find(stateKey) == whatIt->second.end()) {
- if (hitGuardRailLocked(eventKey)) {
- return;
- }
- mCurrentSlicedDurationTrackerMap[whatKey][stateKey] = createDurationTracker(eventKey);
- }
+ mCurrentSlicedDurationTrackerMap[whatKey] = createDurationTracker(eventKey);
}
- auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(stateKey);
+ auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (mUseWhatDimensionAsInternalDimension) {
it->second->noteStart(whatKey, condition,
event.GetElapsedTimestampNs(), conditionKeys);
@@ -560,18 +509,14 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
// Handles Stopall events.
if (matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->noteStopAll(event.GetElapsedTimestampNs());
- }
+ whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
}
return;
}
- HashableDimensionKey dimensionInWhat;
+ HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
if (!mDimensionsInWhat.empty()) {
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
- } else {
- dimensionInWhat = DEFAULT_DIMENSION_KEY;
}
// Handles Stop events.
@@ -579,9 +524,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
- }
+ whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -593,10 +536,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& stateIt : whatIt->second) {
- stateIt.second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(),
- false);
- }
+ whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
}
return;
}
@@ -619,8 +559,8 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
condition = condition && mIsActive;
- handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
+ handleStartEvent(MetricDimensionKey(dimensionInWhat, DEFAULT_DIMENSION_KEY), conditionKey,
+ condition, event);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 45908fb48f75..06da0f64aedb 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -132,8 +132,7 @@ private:
std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The duration trackers in the current bucket.
- std::unordered_map<HashableDimensionKey,
- std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>>
+ std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
mCurrentSlicedDurationTrackerMap;
// Helper function to create a duration tracker given the metric aggregation type.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 6b5c2994a0c8..afe93d445e1d 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -82,8 +82,6 @@ public:
virtual ~DurationTracker(){};
- virtual unique_ptr<DurationTracker> clone(const int64_t eventTime) = 0;
-
virtual void noteStart(const HashableDimensionKey& key, bool condition,
const int64_t eventTime, const ConditionKey& conditionKey) = 0;
virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index df66cb0c53e5..2be5855e90e6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -37,24 +37,6 @@ MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
conditionSliced, fullLink, anomalyTrackers) {
}
-unique_ptr<DurationTracker> MaxDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<MaxDurationTracker>(*this);
- for (auto it = clonedTracker->mInfos.begin(); it != clonedTracker->mInfos.end();) {
- if (it->second.state != kStopped) {
- it->second.lastStartTime = eventTime;
- it->second.lastDuration = 0;
- it++;
- } else {
- it = clonedTracker->mInfos.erase(it);
- }
- }
- if (clonedTracker->mInfos.empty()) {
- return nullptr;
- } else {
- return clonedTracker;
- }
-}
-
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
if (mInfos.find(newKey) != mInfos.end()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index d0371da096ea..efb8dc70afd1 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -38,8 +38,6 @@ public:
MaxDurationTracker(const MaxDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index b0fd975b2328..57f39656fdfe 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -38,13 +38,6 @@ OringDurationTracker::OringDurationTracker(
mLastStartTime = 0;
}
-unique_ptr<DurationTracker> OringDurationTracker::clone(const int64_t eventTime) {
- auto clonedTracker = make_unique<OringDurationTracker>(*this);
- clonedTracker->mLastStartTime = eventTime;
- clonedTracker->mDuration = 0;
- return clonedTracker;
-}
-
bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 43c48d5f536b..c3aad668aa78 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -37,8 +37,6 @@ public:
OringDurationTracker(const OringDurationTracker& tracker) = default;
- unique_ptr<DurationTracker> clone(const int64_t eventTime) override;
-
void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index a9a105f0fda7..a37cad14fcbc 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -69,12 +69,6 @@ void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
}
}
-void SubscriberReporter::removeConfig(const ConfigKey& configKey) {
- VLOG("SubscriberReporter::removeConfig called.");
- lock_guard<std::mutex> lock(mLock);
- mIntentMap.erase(configKey);
-}
-
void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
const Subscription& subscription,
const MetricDimensionKey& dimKey) const {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 8ccc8ee626d4..087a1b84b91f 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -59,9 +59,6 @@ public:
*/
void unsetBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
- /** Remove all information stored by SubscriberReporter about the given config. */
- void removeConfig(const ConfigKey& configKey);
-
/**
* Sends a broadcast via the intentSender previously stored for the
* given (configKey, subscriberId) pair by setBroadcastSubscriber.
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 0bc3ebb81ce6..16b51d99535b 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -28,16 +28,16 @@ namespace statsd {
#ifdef __ANDROID__
-const string kAndroid = "android";
const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
+const int kCallingUid = 0; // Randomly chosen
void SendConfig(StatsService& service, const StatsdConfig& config) {
string str;
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
- service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
+ service.addConfiguration(kConfigKey, configAsVec, kCallingUid);
}
ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
@@ -50,7 +50,7 @@ ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestam
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
- return reports.reports(0);
+ return reports.reports(kCallingUid);
}
StatsdConfig MakeConfig() {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 49c389a0c4a7..1278ff6817fd 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -16,7 +16,9 @@
package android.app;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -40,11 +42,13 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.provider.BaseColumns;
import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
+import android.util.LongSparseArray;
import android.util.Pair;
import java.io.File;
@@ -1069,6 +1073,37 @@ public class DownloadManager {
}
/**
+ * Notify {@link DownloadManager} that the given {@link MediaStore} items
+ * were just deleted so that {@link DownloadManager} internal data
+ * structures can be cleaned up.
+ *
+ * @param idToMime map from {@link BaseColumns#_ID} to
+ * {@link ContentResolver#getType(Uri)}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
+ public void onMediaStoreDownloadsDeleted(@NonNull LongSparseArray<String> idToMime) {
+ try (ContentProviderClient client = mResolver
+ .acquireUnstableContentProviderClient(mBaseUri)) {
+ final Bundle callExtras = new Bundle();
+ final long[] ids = new long[idToMime.size()];
+ final String[] mimeTypes = new String[idToMime.size()];
+ for (int i = idToMime.size() - 1; i >= 0; --i) {
+ ids[i] = idToMime.keyAt(i);
+ mimeTypes[i] = idToMime.valueAt(i);
+ }
+ callExtras.putLongArray(android.provider.Downloads.EXTRA_IDS, ids);
+ callExtras.putStringArray(android.provider.Downloads.EXTRA_MIME_TYPES,
+ mimeTypes);
+ client.call(android.provider.Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED,
+ null, callExtras);
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ }
+
+ /**
* Enqueue a new download. The download will start automatically once the download manager is
* ready to execute it and connectivity is available.
*
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 83d1de60cac7..84263749232d 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -157,11 +157,11 @@ public final class StatsManager {
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
// can throw IllegalArgumentException
service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when adding configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when adding configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -194,10 +194,10 @@ public final class StatsManager {
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when removing configuration");
+ Slog.e(TAG, "Failed to connect to statsmanager when removing configuration");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -390,10 +390,10 @@ public final class StatsManager {
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting data");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting data");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -427,10 +427,10 @@ public final class StatsManager {
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to connect to statsd when getting metadata");
+ Slog.e(TAG, "Failed to connect to statsmanager when getting metadata");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -462,21 +462,19 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
- IStatsd service = getIStatsdLocked();
+ IStatsManagerService service = getIStatsManagerServiceLocked();
if (service == null) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
- }
- return new long[0];
+ throw new StatsUnavailableException("Failed to find statsmanager when "
+ + "getting experiment IDs");
}
return service.getRegisteredExperimentIds();
} catch (RemoteException e) {
if (DEBUG) {
Slog.d(TAG,
- "Failed to connect to StatsCompanionService when getting "
+ "Failed to connect to StatsManagerService when getting "
+ "registered experiment IDs");
}
- return new long[0];
+ throw new StatsUnavailableException("could not connect", e);
}
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index a1765c85d57b..078e4538c66b 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -153,6 +153,11 @@ public class StatusBarManager {
*/
public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS;
+ /**
+ * disable flags to be applied when the device is sim-locked.
+ */
+ private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND;
+
/** @hide */
public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0;
/** @hide */
@@ -385,6 +390,30 @@ public class StatusBarManager {
}
/**
+ * Enable or disable expansion of the status bar. When the device is SIM-locked, the status
+ * bar should not be expandable.
+ *
+ * @param disabled If {@code true}, the status bar will be set to non-expandable. If
+ * {@code false}, re-enables expansion of the status bar.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ public void setDisabledForSimNetworkLock(boolean disabled) {
+ try {
+ final int userId = Binder.getCallingUserHandle().getIdentifier();
+ final IStatusBarService svc = getService();
+ if (svc != null) {
+ svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE,
+ mToken, mContext.getPackageName(), userId);
+ }
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get this app's currently requested disabled components
*
* @return a new DisableInfo
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f3028a10bb10..2aac94c6f5da 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -88,7 +88,6 @@ import android.telephony.data.ApnSetting;
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
@@ -6757,6 +6756,34 @@ public class DevicePolicyManager {
}
/**
+ * @hide
+ * Privileged apps can use this method to find out if the device was provisioned as
+ * organization-owend device with a managed profile.
+ *
+ * This, together with checking whether the device has a device owner (by calling
+ * {@link #isDeviceManaged()}), could be used to learn whether the device is owned by an
+ * organization or an individual:
+ * If this method returns true OR {@link #isDeviceManaged()} returns true, then
+ * the device is owned by an organization. Otherwise, it's owned by an individual.
+ *
+ * @return {@code true} if the device was provisioned as organization-owned device,
+ * {@code false} otherwise.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ throwIfParentInstance("isOrganizationOwnedDeviceWithManagedProfile");
+ if (mService != null) {
+ try {
+ return mService.isOrganizationOwnedDeviceWithManagedProfile();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns whether the specified package can read the device identifiers.
*
* @param packageName The package name of the app to check for device identifier access.
@@ -11215,12 +11242,12 @@ public class DevicePolicyManager {
* #setCrossProfilePackages(ComponentName, Set)}.</li>
* <li>The default package names set by the OEM that are allowed to request user consent for
* cross-profile communication without being explicitly enabled by the admin, via
- * {@link R.array#cross_profile_apps}</li>
+ * {@link com.android.internal.R.array#cross_profile_apps}</li>
* </ul>
*
* @return the combined set of whitelisted package names set via
* {@link #setCrossProfilePackages(ComponentName, Set)} and
- * {@link R.array#cross_profile_apps}
+ * {@link com.android.internal.R.array#cross_profile_apps}
*
* @hide
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 55dfe2fec4c9..3eec46bd010e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -156,6 +156,7 @@ interface IDevicePolicyManager {
void setProfileName(in ComponentName who, String profileName);
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean isOrganizationOwnedDeviceWithManagedProfile();
boolean checkDeviceIdentifierAccess(in String packageName, int pid, int uid);
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 55f92be14cd0..50de73855511 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index 4c55ba12d881..17e9c5a79fa5 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 4a89a1245473..479e4b4efb4c 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index af9ece00f491..54dd1bed5361 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -24,8 +24,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.util.Log;
-import android.util.TimestampedValue;
/**
* The interface through which system components can send signals to the TimeDetectorService.
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 393d48891d64..85826fd4e669 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -27,6 +27,7 @@ import static android.os.Trace.TRACE_TAG_DATABASE;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.AppOpsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.PackageManager;
@@ -942,7 +943,18 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return null;
}
- /** {@hide} */
+ /**
+ * Return the package name of the caller that initiated the request being
+ * processed on the current thread. The returned package will have
+ * <em>not</em> been verified to belong to the calling UID. Returns
+ * {@code null} if not currently processing a request.
+ * <p>
+ * This will always return {@code null} when processing
+ * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+ *
+ * @see Binder#getCallingUid()
+ * @see Context#grantUriPermission(String, Uri, int)
+ */
public final @Nullable String getCallingPackageUnchecked() {
final Pair<String, String> pkg = mCallingPackage.get();
if (pkg != null) {
@@ -952,7 +964,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return null;
}
- /** {@hide} */
+ /**
+ * Called whenever the value of {@link #getCallingPackage()} changes, giving
+ * the provider an opportunity to invalidate any security related caching it
+ * may be performing.
+ * <p>
+ * This typically happens when a {@link ContentProvider} makes a nested call
+ * back into itself when already processing a call from a remote process.
+ */
public void onCallingPackageChanged() {
}
@@ -1390,8 +1409,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* @param uri The URI to query. This will be the full URI sent by the client.
* @param projection The list of columns to put into the cursor.
* If {@code null} provide a default set of columns.
- * @param queryArgs A Bundle containing all additional information necessary for the query.
- * Values in the Bundle may include SQL style arguments.
+ * @param queryArgs A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @param cancellationSignal A signal to cancel the operation in progress,
* or {@code null}.
* @return a Cursor or {@code null}.
@@ -1525,8 +1547,24 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return false;
}
- /** {@hide} */
+ /**
+ * Perform a detailed internal check on a {@link Uri} to determine if a UID
+ * is able to access it with specific mode flags.
+ * <p>
+ * This method is typically used when the provider implements more dynamic
+ * access controls that cannot be expressed with {@code <path-permission>}
+ * style static rules.
+ *
+ * @param uri the {@link Uri} to perform an access check on.
+ * @param uid the UID to check the permission for.
+ * @param modeFlags the access flags to use for the access check, such as
+ * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+ * @return {@link PackageManager#PERMISSION_GRANTED} if access is allowed,
+ * otherwise {@link PackageManager#PERMISSION_DENIED}.
+ * @hide
+ */
@Override
+ @SystemApi
public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
return PackageManager.PERMISSION_DENIED;
}
@@ -1574,9 +1612,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
*
* @param uri The content:// URI of the insertion request.
* @param values A set of column_name/value pairs to add to the database.
- * @param extras A Bundle containing all additional information necessary
- * for the insert.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return The URI for the newly inserted item.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values,
@@ -1653,10 +1696,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
*
* @param uri The full URI to query, including a row ID (if a specific
* record is requested).
- * @param extras A Bundle containing all additional information necessary
- * for the delete. Values in the Bundle may include SQL style
- * arguments.
- * @return The number of rows affected.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
* @throws SQLException
*/
@Override
@@ -1699,10 +1745,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* @param uri The URI to query. This can potentially have a record ID if
* this is an update request for a specific record.
* @param values A set of column_name/value pairs to update in the database.
- * @param extras A Bundle containing all additional information necessary
- * for the update. Values in the Bundle may include SQL style
- * arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the number of rows affected.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values,
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index 11dda83a6e6c..4fb1ddb958d5 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -36,7 +36,7 @@ public class ContentProviderResult implements Parcelable {
public final @Nullable Uri uri;
public final @Nullable Integer count;
public final @Nullable Bundle extras;
- public final @Nullable Exception exception;
+ public final @Nullable Throwable exception;
public ContentProviderResult(@NonNull Uri uri) {
this(Objects.requireNonNull(uri), null, null, null);
@@ -50,12 +50,12 @@ public class ContentProviderResult implements Parcelable {
this(null, null, Objects.requireNonNull(extras), null);
}
- public ContentProviderResult(@NonNull Exception exception) {
+ public ContentProviderResult(@NonNull Throwable exception) {
this(null, null, null, exception);
}
/** {@hide} */
- public ContentProviderResult(Uri uri, Integer count, Bundle extras, Exception exception) {
+ public ContentProviderResult(Uri uri, Integer count, Bundle extras, Throwable exception) {
this.uri = uri;
this.count = count;
this.extras = extras;
@@ -79,7 +79,7 @@ public class ContentProviderResult implements Parcelable {
extras = null;
}
if (source.readInt() != 0) {
- exception = (Exception) ParcelableException.readFromParcel(source);
+ exception = ParcelableException.readFromParcel(source);
} else {
exception = null;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 1d3c6505f677..6cd1cd3354c2 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -984,7 +984,11 @@ public abstract class ContentResolver implements ContentInterface {
* retrieve.
* @param projection A list of which columns to return. Passing null will
* return all columns, which is inefficient.
- * @param queryArgs A Bundle containing any arguments to the query.
+ * @param queryArgs A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
@@ -1925,9 +1929,15 @@ public abstract class ContentResolver implements ContentInterface {
* @param url The URL of the table to insert into.
* @param values The initial values for the newly inserted row. The key is the column name for
* the field. Passing an empty ContentValues will create an empty row.
- * @param extras A Bundle containing all additional information necessary for the insert.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the URL of the newly created row. May return <code>null</code> if the underlying
* content provider returns <code>null</code>, or if it crashes.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@@ -2061,9 +2071,14 @@ public abstract class ContentResolver implements ContentInterface {
* If the content provider supports transactions, the deletion will be atomic.
*
* @param url The URL of the row to delete.
- * @param extras A Bundle containing all additional information necessary for the delete.
- * Values in the Bundle may include SQL style arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return The number of rows deleted.
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable Bundle extras) {
@@ -2121,10 +2136,15 @@ public abstract class ContentResolver implements ContentInterface {
* @param uri The URI to modify.
* @param values The new field values. The key is the column name for the field.
A null value will remove an existing field value.
- * @param extras A Bundle containing all additional information necessary for the update.
- * Values in the Bundle may include SQL style arguments.
+ * @param extras A Bundle containing additional information necessary for
+ * the operation. Arguments may include SQL style arguments, such
+ * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
+ * the documentation for each individual provider will indicate
+ * which arguments they support.
* @return the number of rows updated.
* @throws NullPointerException if uri or values are null
+ * @throws IllegalArgumentException if the provider doesn't support one of
+ * the requested Bundle arguments.
*/
@Override
public final int update(@RequiresPermission.Write @NonNull Uri uri,
@@ -3851,15 +3871,47 @@ public abstract class ContentResolver implements ContentInterface {
}
}
+ /**
+ * Decode a path generated by {@link #encodeToFile(Uri)} back into
+ * the original {@link Uri}.
+ * <p>
+ * This is used to offer a way to intercept filesystem calls in
+ * {@link ContentProvider} unaware code and redirect them to a
+ * {@link ContentProvider} when they attempt to use {@code _DATA} columns
+ * that are otherwise deprecated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static @NonNull Uri decodeFromFile(@NonNull File file) {
+ return translateDeprecatedDataPath(file.getAbsolutePath());
+ }
+
+ /**
+ * Encode a {@link Uri} into an opaque filesystem path which can then be
+ * resurrected by {@link #decodeFromFile(File)}.
+ * <p>
+ * This is used to offer a way to intercept filesystem calls in
+ * {@link ContentProvider} unaware code and redirect them to a
+ * {@link ContentProvider} when they attempt to use {@code _DATA} columns
+ * that are otherwise deprecated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static @NonNull File encodeToFile(@NonNull Uri uri) {
+ return new File(translateDeprecatedDataPath(uri));
+ }
+
/** {@hide} */
- public static Uri translateDeprecatedDataPath(String path) {
+ public static @NonNull Uri translateDeprecatedDataPath(@NonNull String path) {
final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length());
return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT)
.encodedOpaquePart(ssp).build().toString());
}
/** {@hide} */
- public static String translateDeprecatedDataPath(Uri uri) {
+ public static @NonNull String translateDeprecatedDataPath(@NonNull Uri uri) {
return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a28868ef38f8..5cb2907dfba4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3391,6 +3391,7 @@ public abstract class Context {
TELEPHONY_SUBSCRIPTION_SERVICE,
CARRIER_CONFIG_SERVICE,
EUICC_SERVICE,
+ MMS_SERVICE,
TELECOM_SERVICE,
CLIPBOARD_SERVICE,
INPUT_METHOD_SERVICE,
@@ -3587,6 +3588,8 @@ public abstract class Context {
* @see android.telephony.CarrierConfigManager
* @see #EUICC_SERVICE
* @see android.telephony.euicc.EuiccManager
+ * @see #MMS_SERVICE
+ * @see android.telephony.MmsManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
* @see #UI_MODE_SERVICE
@@ -4016,6 +4019,7 @@ public abstract class Context {
* @see android.net.wifi.WifiCondManager
* @hide
*/
+ @SystemApi
public static final String WIFI_COND_SERVICE = "wificond";
/**
@@ -4262,6 +4266,15 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.telephony.MmsManager} to send/receive MMS messages.
+ *
+ * @see #getSystemService(String)
+ * @see android.telephony.MmsManager
+ */
+ public static final String MMS_SERVICE = "mms";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.content.ClipboardManager} for accessing and modifying
* the contents of the global clipboard.
*
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index bba14c39de72..36ec67ee1471 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -35,8 +35,8 @@ import com.android.internal.util.ArrayUtils;
import libcore.util.EmptyArray;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
@@ -56,7 +56,7 @@ public class SQLiteQueryBuilder {
"(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)");
private Map<String, String> mProjectionMap = null;
- private List<Pattern> mProjectionGreylist = null;
+ private Collection<Pattern> mProjectionGreylist = null;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mTables = "";
@@ -196,20 +196,16 @@ public class SQLiteQueryBuilder {
* Sets a projection greylist of columns that will be allowed through, even
* when {@link #setStrict(boolean)} is enabled. This provides a way for
* abusive custom columns like {@code COUNT(*)} to continue working.
- *
- * @hide
*/
- public void setProjectionGreylist(@Nullable List<Pattern> projectionGreylist) {
+ public void setProjectionGreylist(@Nullable Collection<Pattern> projectionGreylist) {
mProjectionGreylist = projectionGreylist;
}
/**
* Gets the projection greylist for the query, as last configured by
- * {@link #setProjectionGreylist(List)}.
- *
- * @hide
+ * {@link #setProjectionGreylist}.
*/
- public @Nullable List<Pattern> getProjectionGreylist() {
+ public @Nullable Collection<Pattern> getProjectionGreylist() {
return mProjectionGreylist;
}
@@ -244,25 +240,27 @@ public class SQLiteQueryBuilder {
}
/**
- * When set, the selection is verified against malicious arguments.
- * When using this class to create a statement using
+ * When set, the selection is verified against malicious arguments. When
+ * using this class to create a statement using
* {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)},
- * non-numeric limits will raise an exception. If a projection map is specified, fields
- * not in that map will be ignored.
- * If this class is used to execute the statement directly using
+ * non-numeric limits will raise an exception. If a projection map is
+ * specified, fields not in that map will be ignored. If this class is used
+ * to execute the statement directly using
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String)}
* or
* {@link #query(SQLiteDatabase, String[], String, String[], String, String, String, String)},
- * additionally also parenthesis escaping selection are caught.
- *
- * To summarize: To get maximum protection against malicious third party apps (for example
- * content provider consumers), make sure to do the following:
+ * additionally also parenthesis escaping selection are caught. To
+ * summarize: To get maximum protection against malicious third party apps
+ * (for example content provider consumers), make sure to do the following:
* <ul>
* <li>Set this value to true</li>
* <li>Use a projection map</li>
- * <li>Use one of the query overloads instead of getting the statement as a sql string</li>
+ * <li>Use one of the query overloads instead of getting the statement as a
+ * sql string</li>
* </ul>
- * By default, this value is false.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrict(boolean strict) {
if (strict) {
@@ -287,6 +285,9 @@ public class SQLiteQueryBuilder {
* This enforcement applies to {@link #insert}, {@link #query}, and
* {@link #update} operations. Any enforcement failures will throw an
* {@link IllegalArgumentException}.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrictColumns(boolean strictColumns) {
if (strictColumns) {
@@ -323,6 +324,9 @@ public class SQLiteQueryBuilder {
* {@link #delete} operations. This enforcement does not apply to trusted
* inputs, such as those provided by {@link #appendWhere}. Any enforcement
* failures will throw an {@link IllegalArgumentException}.
+ * <p>
+ * This feature is disabled by default on each newly constructed
+ * {@link SQLiteQueryBuilder} and needs to be manually enabled.
*/
public void setStrictGrammar(boolean strictGrammar) {
if (strictGrammar) {
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 73b9d1739061..67fdda37ed3b 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -91,7 +91,7 @@ public class UsbManager {
*
* {@hide}
*/
- @UnsupportedAppUsage
+ @SystemApi
public static final String ACTION_USB_STATE =
"android.hardware.usb.action.USB_STATE";
@@ -164,7 +164,7 @@ public class UsbManager {
*
* {@hide}
*/
- @UnsupportedAppUsage
+ @SystemApi
public static final String USB_CONNECTED = "connected";
/**
@@ -181,6 +181,7 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
public static final String USB_CONFIGURED = "configured";
/**
@@ -217,6 +218,7 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
public static final String USB_FUNCTION_RNDIS = "rndis";
/**
@@ -319,6 +321,7 @@ public class UsbManager {
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
* {@hide}
*/
+ @SystemApi
public static final long FUNCTION_NONE = 0;
/**
@@ -337,6 +340,7 @@ public class UsbManager {
* Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
* {@hide}
*/
+ @SystemApi
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
/**
@@ -698,6 +702,8 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
public void setCurrentFunctions(long functions) {
try {
mService.setCurrentFunctions(functions);
@@ -737,6 +743,8 @@ public class UsbManager {
*
* {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_USB)
public long getCurrentFunctions() {
try {
return mService.getCurrentFunctions();
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
new file mode 100644
index 000000000000..6afdb5ef1b16
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * Class that provides utilities for collecting network connectivity diagnostics information.
+ * Connectivity information is made available through triggerable diagnostics tools and by listening
+ * to System validations. Some diagnostics information may be permissions-restricted.
+ *
+ * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
+ * connectivity on a user device. These tools will provide several mechanisms for these applications
+ * to be alerted to network conditions as well as diagnose potential network issues themselves.
+ *
+ * <p>The primary responsibilities of this class are to:
+ *
+ * <ul>
+ * <li>Allow permissioned applications to register and unregister callbacks for network event
+ * notifications
+ * <li>Invoke callbacks for network event notifications, including:
+ * <ul>
+ * <li>Network validations
+ * <li>Data stalls
+ * <li>Connectivity reports from applications
+ * </ul>
+ * </ul>
+ */
+public class ConnectivityDiagnosticsManager {
+ public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+ public static final int DETECTION_METHOD_TCP_METRICS = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"DETECTION_METHOD_"},
+ value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
+ public @interface DetectionMethod {}
+
+ /** @hide */
+ public ConnectivityDiagnosticsManager() {}
+
+ /** Class that includes connectivity information for a specific Network at a specific time. */
+ public static class ConnectivityReport {
+ /** The Network for which this ConnectivityReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** LinkProperties available on the Network at the reported timestamp */
+ @NonNull public final LinkProperties linkProperties;
+
+ /** NetworkCapabilities available on the Network at the reported timestamp */
+ @NonNull public final NetworkCapabilities networkCapabilities;
+
+ /** PersistableBundle that may contain additional info about the report */
+ @NonNull public final PersistableBundle additionalInfo;
+
+ /**
+ * Constructor for ConnectivityReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onConnectivityReport} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this ConnectivityReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param linkProperties The LinkProperties available on network at reportTimestamp
+ * @param networkCapabilities The NetworkCapabilities available on network at
+ * reportTimestamp
+ * @param additionalInfo A PersistableBundle that may contain additional info about the
+ * report
+ */
+ public ConnectivityReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull PersistableBundle additionalInfo) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.linkProperties = linkProperties;
+ this.networkCapabilities = networkCapabilities;
+ this.additionalInfo = additionalInfo;
+ }
+ }
+
+ /** Class that includes information for a suspected data stall on a specific Network */
+ public static class DataStallReport {
+ /** The Network for which this DataStallReport applied */
+ @NonNull public final Network network;
+
+ /**
+ * The timestamp for the report. The timestamp is taken from {@link
+ * System#currentTimeMillis}.
+ */
+ public final long reportTimestamp;
+
+ /** The detection method used to identify the suspected data stall */
+ @DetectionMethod public final int detectionMethod;
+
+ /** PersistableBundle that may contain additional information on the suspected data stall */
+ @NonNull public final PersistableBundle stallDetails;
+
+ /**
+ * Constructor for DataStallReport.
+ *
+ * <p>Apps should obtain instances through {@link
+ * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
+ * instances (unless for testing purposes).
+ *
+ * @param network The Network for which this DataStallReport applies
+ * @param reportTimestamp The timestamp for the report
+ * @param detectionMethod The detection method used to identify this data stall
+ * @param stallDetails A PersistableBundle that may contain additional info about the report
+ */
+ public DataStallReport(
+ @NonNull Network network,
+ long reportTimestamp,
+ @DetectionMethod int detectionMethod,
+ @NonNull PersistableBundle stallDetails) {
+ this.network = network;
+ this.reportTimestamp = reportTimestamp;
+ this.detectionMethod = detectionMethod;
+ this.stallDetails = stallDetails;
+ }
+ }
+
+ /**
+ * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
+ * network connectivity events. Must be extended by applications wanting notifications.
+ */
+ public abstract static class ConnectivityDiagnosticsCallback {
+ /**
+ * Called when the platform completes a data connectivity check. This will also be invoked
+ * upon registration with the latest report.
+ *
+ * <p>The Network specified in the ConnectivityReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The ConnectivityReport containing information about a connectivity check
+ */
+ public void onConnectivityReport(@NonNull ConnectivityReport report) {}
+
+ /**
+ * Called when the platform suspects a data stall on some Network.
+ *
+ * <p>The Network specified in the DataStallReport may not be active any more when this
+ * method is invoked.
+ *
+ * @param report The DataStallReport containing information about the suspected data stall
+ */
+ public void onDataStallSuspected(@NonNull DataStallReport report) {}
+
+ /**
+ * Called when any app reports connectivity to the System.
+ *
+ * @param network The Network for which connectivity has been reported
+ * @param hasConnectivity The connectivity reported to the System
+ */
+ public void onNetworkConnectivityReported(
+ @NonNull Network network, boolean hasConnectivity) {}
+ }
+
+ /**
+ * Registers a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>Only apps that offer network connectivity to the user are allowed to register callbacks.
+ * This includes:
+ *
+ * <ul>
+ * <li>Carrier apps with active subscriptions
+ * <li>Active VPNs
+ * <li>WiFi Suggesters
+ * </ul>
+ *
+ * <p>Callbacks will be limited to receiving notifications for networks over which apps provide
+ * connectivity.
+ *
+ * <p>If a registering app loses its relevant permissions, any callbacks it registered will
+ * silently stop receiving callbacks.
+ *
+ * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If
+ * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException
+ * will be thrown.
+ *
+ * @param request The NetworkRequest that will be used to match with Networks for which
+ * callbacks will be fired
+ * @param e The Executor to be used for running the callback method invocations
+ * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
+ * System
+ * @throws IllegalArgumentException if the same callback instance is registered with multiple
+ * NetworkRequests
+ * @throws SecurityException if the caller does not have appropriate permissions to register a
+ * callback
+ */
+ public void registerConnectivityDiagnosticsCallback(
+ @NonNull NetworkRequest request,
+ @NonNull Executor e,
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+
+ /**
+ * Unregisters a ConnectivityDiagnosticsCallback with the System.
+ *
+ * <p>If the given callback is not currently registered with the System, this operation will be
+ * a no-op.
+ *
+ * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
+ */
+ public void unregisterConnectivityDiagnosticsCallback(
+ @NonNull ConnectivityDiagnosticsCallback callback) {
+ // TODO(b/143187964): implement ConnectivityDiagnostics functionality
+ throw new UnsupportedOperationException("registerCallback() not supported yet");
+ }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6da16a82c822..9223ccd54251 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -363,7 +363,7 @@ public class ConnectivityManager {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage
public static final String ACTION_TETHER_STATE_CHANGED =
- "android.net.conn.TETHER_STATE_CHANGED";
+ TetheringManager.ACTION_TETHER_STATE_CHANGED;
/**
* @hide
@@ -371,14 +371,14 @@ public class ConnectivityManager {
* tethering and currently available for tethering.
*/
@UnsupportedAppUsage
- public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER;
/**
* @hide
* gives a String[] listing all the interfaces currently in local-only
* mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
*/
- public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
/**
* @hide
@@ -386,7 +386,7 @@ public class ConnectivityManager {
* (ie, has DHCPv4 support and packets potentially forwarded/NATed)
*/
@UnsupportedAppUsage
- public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER;
/**
* @hide
@@ -395,7 +395,7 @@ public class ConnectivityManager {
* for any interfaces listed here.
*/
@UnsupportedAppUsage
- public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER;
/**
* Broadcast Action: The captive portal tracker has finished its test.
@@ -445,7 +445,7 @@ public class ConnectivityManager {
* @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
- public static final int TETHERING_INVALID = -1;
+ public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID;
/**
* Wifi tethering type.
@@ -453,7 +453,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_WIFI = 0;
+ public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI;
/**
* USB tethering type.
@@ -461,7 +461,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_USB = 1;
+ public static final int TETHERING_USB = TetheringManager.TETHERING_USB;
/**
* Bluetooth tethering type.
@@ -469,7 +469,7 @@ public class ConnectivityManager {
* @hide
*/
@SystemApi
- public static final int TETHERING_BLUETOOTH = 2;
+ public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH;
/**
* Wifi P2p tethering type.
@@ -477,41 +477,41 @@ public class ConnectivityManager {
* need to start from #startTethering(int, boolean, OnStartTetheringCallback).
* @hide
*/
- public static final int TETHERING_WIFI_P2P = 3;
+ public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P;
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
* @hide
*/
- public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+ public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. Includes the type of tethering for
* which to cancel provisioning.
* @hide
*/
- public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+ public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. True to schedule a recheck of tether
* provisioning.
* @hide
*/
- public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+ public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM;
/**
* Tells the TetherService to run a provision check now.
* @hide
*/
- public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+ public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION;
/**
* Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
* which will receive provisioning results. Can be left empty.
* @hide
*/
- public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+ public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK;
/**
* The absence of a connection type.
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 45bf4d2e1358..96d7a80886a5 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -19,6 +19,9 @@ package android.net;
import static android.os.Process.CLAT_UID;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,59 +51,104 @@ import java.util.function.Predicate;
* @hide
*/
// @NotThreadSafe
-public class NetworkStats implements Parcelable {
+@SystemApi
+public final class NetworkStats implements Parcelable {
private static final String TAG = "NetworkStats";
+
/** {@link #iface} value when interface details unavailable. */
- public static final String IFACE_ALL = null;
+ @SuppressLint("CompileTimeConstant")
+ @Nullable public static final String IFACE_ALL = null;
+ /**
+ * Virtual network interface for video telephony. This is for VT data usage counting
+ * purpose.
+ */
+ public static final String IFACE_VT = "vt_data0";
+
/** {@link #uid} value when UID details unavailable. */
public static final int UID_ALL = -1;
- /** {@link #tag} value matching any tag. */
+ /** Special UID value for data usage by tethering. */
+ public static final int UID_TETHERING = -5;
+
+ /**
+ * {@link #tag} value matching any tag.
+ * @hide
+ */
// TODO: Rename TAG_ALL to TAG_ANY.
public static final int TAG_ALL = -1;
- /** {@link #set} value for all sets combined, not including debug sets. */
+ /**
+ * {@link #set} value for all sets combined, not including debug sets.
+ * @hide
+ */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
public static final int SET_DEFAULT = 0;
/** {@link #set} value where foreground data is accounted. */
public static final int SET_FOREGROUND = 1;
- /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
+ /**
+ * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values.
+ * @hide
+ */
public static final int SET_DEBUG_START = 1000;
- /** Debug {@link #set} value when the VPN stats are moved in. */
+ /**
+ * Debug {@link #set} value when the VPN stats are moved in.
+ * @hide
+ */
public static final int SET_DBG_VPN_IN = 1001;
- /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
+ /**
+ * Debug {@link #set} value when the VPN stats are moved out of a vpn UID.
+ * @hide
+ */
public static final int SET_DBG_VPN_OUT = 1002;
- /** Include all interfaces when filtering */
- public static final String[] INTERFACES_ALL = null;
+ /**
+ * Include all interfaces when filtering
+ * @hide
+ */
+ public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
// TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
- /** {@link #metered} value to account for all metered states. */
+ /**
+ * {@link #metered} value to account for all metered states.
+ * @hide
+ */
public static final int METERED_ALL = -1;
/** {@link #metered} value where native, unmetered data is accounted. */
public static final int METERED_NO = 0;
/** {@link #metered} value where metered data is accounted. */
public static final int METERED_YES = 1;
- /** {@link #roaming} value to account for all roaming states. */
+ /**
+ * {@link #roaming} value to account for all roaming states.
+ * @hide
+ */
public static final int ROAMING_ALL = -1;
/** {@link #roaming} value where native, non-roaming data is accounted. */
public static final int ROAMING_NO = 0;
/** {@link #roaming} value where roaming data is accounted. */
public static final int ROAMING_YES = 1;
- /** {@link #onDefaultNetwork} value to account for all default network states. */
+ /**
+ * {@link #onDefaultNetwork} value to account for all default network states.
+ * @hide
+ */
public static final int DEFAULT_NETWORK_ALL = -1;
/** {@link #onDefaultNetwork} value to account for usage while not the default network. */
public static final int DEFAULT_NETWORK_NO = 0;
/** {@link #onDefaultNetwork} value to account for usage while the default network. */
public static final int DEFAULT_NETWORK_YES = 1;
- /** Denotes a request for stats at the interface level. */
+ /**
+ * Denotes a request for stats at the interface level.
+ * @hide
+ */
public static final int STATS_PER_IFACE = 0;
- /** Denotes a request for stats at the interface and UID level. */
+ /**
+ * Denotes a request for stats at the interface and UID level.
+ * @hide
+ */
public static final int STATS_PER_UID = 1;
private static final String CLATD_INTERFACE_PREFIX = "v4-";
@@ -144,60 +192,78 @@ public class NetworkStats implements Parcelable {
@UnsupportedAppUsage
private long[] operations;
+ /** @hide */
+ @SystemApi
public static class Entry {
+ /** @hide */
@UnsupportedAppUsage
public String iface;
+ /** @hide */
@UnsupportedAppUsage
public int uid;
+ /** @hide */
@UnsupportedAppUsage
public int set;
+ /** @hide */
@UnsupportedAppUsage
public int tag;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int metered;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int roaming;
/**
* Note that this is only populated w/ the default value when read from /proc or written
* to disk. We merge in the correct value when reporting this value to clients of
* getSummary().
+ * @hide
*/
public int defaultNetwork;
+ /** @hide */
@UnsupportedAppUsage
public long rxBytes;
+ /** @hide */
@UnsupportedAppUsage
public long rxPackets;
+ /** @hide */
@UnsupportedAppUsage
public long txBytes;
+ /** @hide */
@UnsupportedAppUsage
public long txPackets;
+ /** @hide */
+ @UnsupportedAppUsage
public long operations;
+ /** @hide */
@UnsupportedAppUsage
public Entry() {
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
}
+ /** @hide */
public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
operations);
}
+ /** @hide */
public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
- public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
+ public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
this.iface = iface;
@@ -214,15 +280,18 @@ public class NetworkStats implements Parcelable {
this.operations = operations;
}
+ /** @hide */
public boolean isNegative() {
return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
}
+ /** @hide */
public boolean isEmpty() {
return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
&& operations == 0;
}
+ /** @hide */
public void add(Entry another) {
this.rxBytes += another.rxBytes;
this.rxPackets += another.rxPackets;
@@ -249,6 +318,7 @@ public class NetworkStats implements Parcelable {
return builder.toString();
}
+ /** @hide */
@Override
public boolean equals(Object o) {
if (o instanceof Entry) {
@@ -262,13 +332,13 @@ public class NetworkStats implements Parcelable {
return false;
}
+ /** @hide */
@Override
public int hashCode() {
return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
}
}
- @UnsupportedAppUsage
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
@@ -292,6 +362,7 @@ public class NetworkStats implements Parcelable {
}
}
+ /** @hide */
@UnsupportedAppUsage
public NetworkStats(Parcel parcel) {
elapsedRealtime = parcel.readLong();
@@ -312,7 +383,7 @@ public class NetworkStats implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
dest.writeInt(capacity);
@@ -330,19 +401,23 @@ public class NetworkStats implements Parcelable {
dest.writeLongArray(operations);
}
+ /**
+ * @hide
+ */
@Override
public NetworkStats clone() {
final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
NetworkStats.Entry entry = null;
for (int i = 0; i < size; i++) {
entry = getValues(i, entry);
- clone.addValues(entry);
+ clone.addEntry(entry);
}
return clone;
}
/**
* Clear all data stored in this object.
+ * @hide
*/
public void clear() {
this.capacity = 0;
@@ -360,25 +435,28 @@ public class NetworkStats implements Parcelable {
this.operations = EmptyArray.LONG;
}
+ /** @hide */
@VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- return addValues(
+ return addEntry(
iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
+ /** @hide */
@VisibleForTesting
- public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
+ public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
- return addValues(new Entry(
+ return addEntry(new Entry(
iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
+ /** @hide */
@VisibleForTesting
- public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
+ public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
- return addValues(new Entry(
+ return addEntry(new Entry(
iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
txBytes, txPackets, operations));
}
@@ -386,8 +464,9 @@ public class NetworkStats implements Parcelable {
/**
* Add new stats entry, copying from given {@link Entry}. The {@link Entry}
* object can be recycled across multiple calls.
+ * @hide
*/
- public NetworkStats addValues(Entry entry) {
+ public NetworkStats addEntry(Entry entry) {
if (size >= capacity) {
final int newLength = Math.max(size, 10) * 3 / 2;
iface = Arrays.copyOf(iface, newLength);
@@ -428,6 +507,7 @@ public class NetworkStats implements Parcelable {
/**
* Return specific stats entry.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getValues(int i, Entry recycle) {
@@ -467,10 +547,12 @@ public class NetworkStats implements Parcelable {
operations[dest] = operations[src];
}
+ /** @hide */
public long getElapsedRealtime() {
return elapsedRealtime;
}
+ /** @hide */
public void setElapsedRealtime(long time) {
elapsedRealtime = time;
}
@@ -478,21 +560,25 @@ public class NetworkStats implements Parcelable {
/**
* Return age of this {@link NetworkStats} object with respect to
* {@link SystemClock#elapsedRealtime()}.
+ * @hide
*/
public long getElapsedRealtimeAge() {
return SystemClock.elapsedRealtime() - elapsedRealtime;
}
+ /** @hide */
@UnsupportedAppUsage
public int size() {
return size;
}
+ /** @hide */
@VisibleForTesting
public int internalSize() {
return capacity;
}
+ /** @hide */
@Deprecated
public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
@@ -501,6 +587,7 @@ public class NetworkStats implements Parcelable {
txPackets, operations);
}
+ /** @hide */
public NetworkStats combineValues(String iface, int uid, int set, int tag,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
return combineValues(new Entry(
@@ -509,16 +596,20 @@ public class NetworkStats implements Parcelable {
/**
* Combine given values with an existing row, or create a new row if
- * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can
- * also be used to subtract values from existing rows.
+ * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
+ * also be used to subtract values from existing rows. This method mutates the referencing
+ * {@link NetworkStats} object.
+ *
+ * @param entry the {@link Entry} to combine.
+ * @return a reference to this mutated {@link NetworkStats} object.
+ * @hide
*/
- @UnsupportedAppUsage
- public NetworkStats combineValues(Entry entry) {
+ public @NonNull NetworkStats combineValues(@NonNull Entry entry) {
final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
entry.roaming, entry.defaultNetwork);
if (i == -1) {
// only create new entry when positive contribution
- addValues(entry);
+ addEntry(entry);
} else {
rxBytes[i] += entry.rxBytes;
rxPackets[i] += entry.rxPackets;
@@ -530,10 +621,33 @@ public class NetworkStats implements Parcelable {
}
/**
+ * Add given values with an existing row, or create a new row if
+ * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
+ * also be used to subtract values from existing rows.
+ *
+ * @param entry the {@link Entry} to add.
+ * @return a new constructed {@link NetworkStats} object that contains the result.
+ */
+ public @NonNull NetworkStats addValues(@NonNull Entry entry) {
+ return this.clone().combineValues(entry);
+ }
+
+ /**
+ * Add the given {@link NetworkStats} objects.
+ *
+ * @return the sum of two objects.
+ */
+ public @NonNull NetworkStats add(@NonNull NetworkStats another) {
+ final NetworkStats ret = this.clone();
+ ret.combineAllValues(another);
+ return ret;
+ }
+
+ /**
* Combine all values from another {@link NetworkStats} into this object.
+ * @hide
*/
- @UnsupportedAppUsage
- public void combineAllValues(NetworkStats another) {
+ public void combineAllValues(@NonNull NetworkStats another) {
NetworkStats.Entry entry = null;
for (int i = 0; i < another.size; i++) {
entry = another.getValues(i, entry);
@@ -543,6 +657,7 @@ public class NetworkStats implements Parcelable {
/**
* Find first stats index that matches the requested parameters.
+ * @hide
*/
public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork) {
@@ -560,6 +675,7 @@ public class NetworkStats implements Parcelable {
/**
* Find first stats index that matches the requested parameters, starting
* search around the hinted index as an optimization.
+ * @hide
*/
@VisibleForTesting
public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
@@ -589,6 +705,7 @@ public class NetworkStats implements Parcelable {
* Splice in {@link #operations} from the given {@link NetworkStats} based
* on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
* since operation counts are at data layer.
+ * @hide
*/
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
@@ -604,6 +721,7 @@ public class NetworkStats implements Parcelable {
/**
* Return list of unique interfaces known by this data structure.
+ * @hide
*/
public String[] getUniqueIfaces() {
final HashSet<String> ifaces = new HashSet<String>();
@@ -617,6 +735,7 @@ public class NetworkStats implements Parcelable {
/**
* Return list of unique UIDs known by this data structure.
+ * @hide
*/
@UnsupportedAppUsage
public int[] getUniqueUids() {
@@ -636,6 +755,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total bytes represented by this snapshot object, usually used when
* checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
+ * @hide
*/
@UnsupportedAppUsage
public long getTotalBytes() {
@@ -645,6 +765,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getTotal(Entry recycle) {
@@ -654,6 +775,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object matching
* the requested {@link #uid}.
+ * @hide
*/
@UnsupportedAppUsage
public Entry getTotal(Entry recycle, int limitUid) {
@@ -663,11 +785,13 @@ public class NetworkStats implements Parcelable {
/**
* Return total of all fields represented by this snapshot object matching
* the requested {@link #iface}.
+ * @hide
*/
public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
return getTotal(recycle, limitIface, UID_ALL, false);
}
+ /** @hide */
@UnsupportedAppUsage
public Entry getTotalIncludingTags(Entry recycle) {
return getTotal(recycle, null, UID_ALL, true);
@@ -717,6 +841,7 @@ public class NetworkStats implements Parcelable {
/**
* Fast path for battery stats.
+ * @hide
*/
public long getTotalPackets() {
long total = 0;
@@ -729,9 +854,12 @@ public class NetworkStats implements Parcelable {
/**
* Subtract the given {@link NetworkStats}, effectively leaving the delta
* between two snapshots in time. Assumes that statistics rows collect over
- * time, and that none of them have disappeared.
+ * time, and that none of them have disappeared. This method does not mutate
+ * the referencing object.
+ *
+ * @return the delta between two objects.
*/
- public NetworkStats subtract(NetworkStats right) {
+ public @NonNull NetworkStats subtract(@NonNull NetworkStats right) {
return subtract(this, right, null, null);
}
@@ -742,6 +870,7 @@ public class NetworkStats implements Parcelable {
* <p>
* If counters have rolled backwards, they are clamped to {@code 0} and
* reported to the given {@link NonMonotonicObserver}.
+ * @hide
*/
public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
NonMonotonicObserver<C> observer, C cookie) {
@@ -759,6 +888,7 @@ public class NetworkStats implements Parcelable {
* If <var>recycle</var> is supplied, this NetworkStats object will be
* reused (and returned) as the result if it is large enough to contain
* the data.
+ * @hide
*/
public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
@@ -817,7 +947,7 @@ public class NetworkStats implements Parcelable {
entry.operations = Math.max(entry.operations, 0);
}
- result.addValues(entry);
+ result.addEntry(entry);
}
return result;
@@ -847,6 +977,7 @@ public class NetworkStats implements Parcelable {
* @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
* @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
* @param useBpfStats True if eBPF is in use.
+ * @hide
*/
public static void apply464xlatAdjustments(NetworkStats baseTraffic,
NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) {
@@ -899,6 +1030,7 @@ public class NetworkStats implements Parcelable {
* {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
* base and stacked traffic.
* @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+ * @hide
*/
public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) {
apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats);
@@ -907,6 +1039,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total statistics grouped by {@link #iface}; doesn't mutate the
* original structure.
+ * @hide
*/
public NetworkStats groupedByIface() {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
@@ -938,6 +1071,7 @@ public class NetworkStats implements Parcelable {
/**
* Return total statistics grouped by {@link #uid}; doesn't mutate the
* original structure.
+ * @hide
*/
public NetworkStats groupedByUid() {
final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
@@ -968,6 +1102,7 @@ public class NetworkStats implements Parcelable {
/**
* Remove all rows that match one of specified UIDs.
+ * @hide
*/
public void removeUids(int[] uids) {
int nextOutputEntry = 0;
@@ -989,6 +1124,7 @@ public class NetworkStats implements Parcelable {
* @param limitUid UID to filter for, or {@link #UID_ALL}.
* @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
* @param limitTag Tag to filter for, or {@link #TAG_ALL}.
+ * @hide
*/
public void filter(int limitUid, String[] limitIfaces, int limitTag) {
if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
@@ -1004,6 +1140,7 @@ public class NetworkStats implements Parcelable {
* Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}.
*
* <p>This mutates the original structure in place.
+ * @hide
*/
public void filterDebugEntries() {
filter(e -> e.set < SET_DEBUG_START);
@@ -1024,6 +1161,7 @@ public class NetworkStats implements Parcelable {
size = nextOutputEntry;
}
+ /** @hide */
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
@@ -1047,6 +1185,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #set} value.
+ * @hide
*/
public static String setToString(int set) {
switch (set) {
@@ -1067,6 +1206,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #set} value.
+ * @hide
*/
public static String setToCheckinString(int set) {
switch (set) {
@@ -1087,6 +1227,7 @@ public class NetworkStats implements Parcelable {
/**
* @return true if the querySet matches the dataSet.
+ * @hide
*/
public static boolean setMatches(int querySet, int dataSet) {
if (querySet == dataSet) {
@@ -1098,6 +1239,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #tag} value.
+ * @hide
*/
public static String tagToString(int tag) {
return "0x" + Integer.toHexString(tag);
@@ -1105,6 +1247,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #metered} value.
+ * @hide
*/
public static String meteredToString(int metered) {
switch (metered) {
@@ -1121,6 +1264,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #roaming} value.
+ * @hide
*/
public static String roamingToString(int roaming) {
switch (roaming) {
@@ -1137,6 +1281,7 @@ public class NetworkStats implements Parcelable {
/**
* Return text description of {@link #defaultNetwork} value.
+ * @hide
*/
public static String defaultNetworkToString(int defaultNetwork) {
switch (defaultNetwork) {
@@ -1151,6 +1296,7 @@ public class NetworkStats implements Parcelable {
}
}
+ /** @hide */
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
@@ -1163,8 +1309,7 @@ public class NetworkStats implements Parcelable {
return 0;
}
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
@Override
public NetworkStats createFromParcel(Parcel in) {
return new NetworkStats(in);
@@ -1176,6 +1321,7 @@ public class NetworkStats implements Parcelable {
}
};
+ /** @hide */
public interface NonMonotonicObserver<C> {
public void foundNonMonotonic(
NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
@@ -1195,6 +1341,7 @@ public class NetworkStats implements Parcelable {
* @param tunUid uid of the VPN application
* @param tunIface iface of the vpn tunnel
* @param underlyingIfaces underlying network ifaces used by the VPN application
+ * @hide
*/
public void migrateTun(int tunUid, @NonNull String tunIface,
@NonNull String[] underlyingIfaces) {
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 162d6e27bd42..8108cf08d5c3 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -89,7 +89,7 @@ public class TrafficStats {
*
* @hide
*/
- public static final int UID_TETHERING = -5;
+ public static final int UID_TETHERING = NetworkStats.UID_TETHERING;
/**
* Tag values in this range are reserved for the network stack. The network stack is
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c9ebed3bd0a2..1a4dac78855f 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1886,29 +1886,7 @@ public final class Parcel {
public final void writeException(@NonNull Exception e) {
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
- int code = 0;
- if (e instanceof Parcelable
- && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
- // We only send Parcelable exceptions that are in the
- // BootClassLoader to ensure that the receiver can unpack them
- code = EX_PARCELABLE;
- } else if (e instanceof SecurityException) {
- code = EX_SECURITY;
- } else if (e instanceof BadParcelableException) {
- code = EX_BAD_PARCELABLE;
- } else if (e instanceof IllegalArgumentException) {
- code = EX_ILLEGAL_ARGUMENT;
- } else if (e instanceof NullPointerException) {
- code = EX_NULL_POINTER;
- } else if (e instanceof IllegalStateException) {
- code = EX_ILLEGAL_STATE;
- } else if (e instanceof NetworkOnMainThreadException) {
- code = EX_NETWORK_MAIN_THREAD;
- } else if (e instanceof UnsupportedOperationException) {
- code = EX_UNSUPPORTED_OPERATION;
- } else if (e instanceof ServiceSpecificException) {
- code = EX_SERVICE_SPECIFIC;
- }
+ int code = getExceptionCode(e);
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
@@ -1922,20 +1900,7 @@ public final class Parcel {
if (sParcelExceptionStackTrace && (timeNow - sLastWriteExceptionStackTrace
> WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS)) {
sLastWriteExceptionStackTrace = timeNow;
- final int sizePosition = dataPosition();
- writeInt(0); // Header size will be filled in later
- StackTraceElement[] stackTrace = e.getStackTrace();
- final int truncatedSize = Math.min(stackTrace.length, 5);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < truncatedSize; i++) {
- sb.append("\tat ").append(stackTrace[i]).append('\n');
- }
- writeString(sb.toString());
- final int payloadPosition = dataPosition();
- setDataPosition(sizePosition);
- // Write stack trace header size. Used in native side to skip the header
- writeInt(payloadPosition - sizePosition);
- setDataPosition(payloadPosition);
+ writeStackTrace(e);
} else {
writeInt(0);
}
@@ -1956,6 +1921,52 @@ public final class Parcel {
}
}
+ /** @hide */
+ public static int getExceptionCode(@NonNull Throwable e) {
+ int code = 0;
+ if (e instanceof Parcelable
+ && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
+ // We only send Parcelable exceptions that are in the
+ // BootClassLoader to ensure that the receiver can unpack them
+ code = EX_PARCELABLE;
+ } else if (e instanceof SecurityException) {
+ code = EX_SECURITY;
+ } else if (e instanceof BadParcelableException) {
+ code = EX_BAD_PARCELABLE;
+ } else if (e instanceof IllegalArgumentException) {
+ code = EX_ILLEGAL_ARGUMENT;
+ } else if (e instanceof NullPointerException) {
+ code = EX_NULL_POINTER;
+ } else if (e instanceof IllegalStateException) {
+ code = EX_ILLEGAL_STATE;
+ } else if (e instanceof NetworkOnMainThreadException) {
+ code = EX_NETWORK_MAIN_THREAD;
+ } else if (e instanceof UnsupportedOperationException) {
+ code = EX_UNSUPPORTED_OPERATION;
+ } else if (e instanceof ServiceSpecificException) {
+ code = EX_SERVICE_SPECIFIC;
+ }
+ return code;
+ }
+
+ /** @hide */
+ public void writeStackTrace(@NonNull Throwable e) {
+ final int sizePosition = dataPosition();
+ writeInt(0); // Header size will be filled in later
+ StackTraceElement[] stackTrace = e.getStackTrace();
+ final int truncatedSize = Math.min(stackTrace.length, 5);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < truncatedSize; i++) {
+ sb.append("\tat ").append(stackTrace[i]).append('\n');
+ }
+ writeString(sb.toString());
+ final int payloadPosition = dataPosition();
+ setDataPosition(sizePosition);
+ // Write stack trace header size. Used in native side to skip the header
+ writeInt(payloadPosition - sizePosition);
+ setDataPosition(payloadPosition);
+ }
+
/**
* Special function for writing information at the front of the Parcel
* indicating that no exception occurred.
@@ -2069,14 +2080,7 @@ public final class Parcel {
if (remoteStackTrace != null) {
RemoteException cause = new RemoteException(
"Remote stack trace:\n" + remoteStackTrace, null, false, false);
- try {
- Throwable rootCause = ExceptionUtils.getRootCause(e);
- if (rootCause != null) {
- rootCause.initCause(cause);
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Cannot set cause " + cause + " for " + e, ex);
- }
+ ExceptionUtils.appendCause(e, cause);
}
SneakyThrow.sneakyThrow(e);
}
@@ -2088,6 +2092,14 @@ public final class Parcel {
* @param msg The exception message.
*/
private Exception createException(int code, String msg) {
+ Exception exception = createExceptionOrNull(code, msg);
+ return exception != null
+ ? exception
+ : new RuntimeException("Unknown exception code: " + code + " msg " + msg);
+ }
+
+ /** @hide */
+ public Exception createExceptionOrNull(int code, String msg) {
switch (code) {
case EX_PARCELABLE:
if (readInt() > 0) {
@@ -2111,9 +2123,9 @@ public final class Parcel {
return new UnsupportedOperationException(msg);
case EX_SERVICE_SPECIFIC:
return new ServiceSpecificException(readInt(), msg);
+ default:
+ return null;
}
- return new RuntimeException("Unknown exception code: " + code
- + " msg " + msg);
}
/**
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 983053bbe7fd..89ddf8cbd96a 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -31,6 +31,9 @@ import static android.system.OsConstants.S_ISLNK;
import static android.system.OsConstants.S_ISREG;
import static android.system.OsConstants.S_IWOTH;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
@@ -253,6 +256,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* be opened with the requested mode.
* @see #parseMode(String)
*/
+ // We can't accept a generic Executor here, since we need to use
+ // MessageQueue.addOnFileDescriptorEventListener()
+ @SuppressLint("ExecutorRegistration")
public static ParcelFileDescriptor open(File file, int mode, Handler handler,
final OnCloseListener listener) throws IOException {
if (handler == null) {
@@ -268,9 +274,22 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
return fromFd(fd, handler, listener);
}
- /** {@hide} */
- public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler,
- final OnCloseListener listener) throws IOException {
+ /**
+ * Create a new ParcelFileDescriptor wrapping an already-opened file.
+ *
+ * @param pfd The already-opened file.
+ * @param handler to call listener from.
+ * @param listener to be invoked when the returned descriptor has been
+ * closed.
+ * @return a new ParcelFileDescriptor pointing to the given file.
+ * @hide
+ */
+ @SystemApi
+ // We can't accept a generic Executor here, since we need to use
+ // MessageQueue.addOnFileDescriptorEventListener()
+ @SuppressLint("ExecutorRegistration")
+ public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd,
+ @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException {
final FileDescriptor original = new FileDescriptor();
original.setInt$(pfd.detachFd());
return fromFd(original, handler, listener);
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index b40283f49408..7a837e167fb0 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -16,17 +16,24 @@
package android.os;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
/**
@@ -339,4 +346,44 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
proto.end(token);
}
+
+ /**
+ * Writes the content of the {@link PersistableBundle} to a {@link OutputStream}.
+ *
+ * <p>The content can be read by a {@link #readFromStream}.
+ *
+ * @see #readFromStream
+ */
+ public void writeToStream(@NonNull OutputStream outputStream) throws IOException {
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(outputStream, UTF_8.name());
+ serializer.startTag(null, "bundle");
+ try {
+ saveToXml(serializer);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ serializer.endTag(null, "bundle");
+ serializer.flush();
+ }
+
+ /**
+ * Reads a {@link PersistableBundle} from an {@link InputStream}.
+ *
+ * <p>The stream must be generated by {@link #writeToStream}.
+ *
+ * @see #writeToStream
+ */
+ @NonNull
+ public static PersistableBundle readFromStream(@NonNull InputStream inputStream)
+ throws IOException {
+ try {
+ XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+ parser.setInput(inputStream, UTF_8.name());
+ parser.next();
+ return PersistableBundle.restoreFromXml(parser);
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 94623bc71346..3ef86ed9f994 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -89,6 +89,12 @@ public class Process {
public static final int DRM_UID = 1019;
/**
+ * Defines the GID for the group that allows write access to the internal media storage.
+ * @hide
+ */
+ public static final int SDCARD_RW_GID = 1015;
+
+ /**
* Defines the UID/GID for the group that controls VPN services.
* @hide
*/
diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java
index 1211dd60f591..064cf7d825b5 100644
--- a/core/java/android/os/TelephonyServiceManager.java
+++ b/core/java/android/os/TelephonyServiceManager.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
/**
* Provides a way to register and obtain the system service binder objects managed by the telephony
@@ -51,8 +52,8 @@ public class TelephonyServiceManager {
/**
* Register a system server binding object for a service.
*/
- public void register(@NonNull IBinder binder) {
- ServiceManager.addService(mServiceName, binder);
+ public void register(@NonNull IBinder service) {
+ ServiceManager.addService(mServiceName, service);
}
/**
@@ -114,25 +115,123 @@ public class TelephonyServiceManager {
*/
@NonNull
public ServiceRegisterer getTelephonyServiceRegisterer() {
- return new ServiceRegisterer("phone");
- }
-
-
-// TODO: Add more services...
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "subscription" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSubscriptionServiceRegisterer() {
-// return new ServiceRegisterer("isub");
-// }
-//
-// /**
-// * Returns {@link ServiceRegisterer} for the "SMS" service.
-// */
-// @NonNull
-// public ServiceRegisterer getSmsServiceRegisterer() {
-// return new ServiceRegisterer("isms");
-// }
+ return new ServiceRegisterer(Context.TELEPHONY_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony registry service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRegistryServiceRegisterer() {
+ return new ServiceRegisterer("telephony.registry");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony IMS service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyImsServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_IMS_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the telephony RCS message service.
+ */
+ @NonNull
+ public ServiceRegisterer getTelephonyRcsMessageServiceRegisterer() {
+ return new ServiceRegisterer(Context.TELEPHONY_RCS_MESSAGE_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the subscription service.
+ */
+ @NonNull
+ public ServiceRegisterer getSubscriptionServiceRegisterer() {
+ return new ServiceRegisterer("isub");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the network policy service.
+ */
+ @NonNull
+ public ServiceRegisterer getNetworkPolicyServiceRegisterer() {
+ return new ServiceRegisterer(Context.NETWORK_POLICY_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the phone sub service.
+ */
+ @NonNull
+ public ServiceRegisterer getPhoneSubServiceRegisterer() {
+ return new ServiceRegisterer("iphonesubinfo");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the opportunistic network service.
+ */
+ @NonNull
+ public ServiceRegisterer getOpportunisticNetworkServiceRegisterer() {
+ return new ServiceRegisterer("ions");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the carrier config service.
+ */
+ @NonNull
+ public ServiceRegisterer getCarrierConfigServiceRegisterer() {
+ return new ServiceRegisterer(Context.CARRIER_CONFIG_SERVICE);
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "SMS" service.
+ */
+ @NonNull
+ public ServiceRegisterer getSmsServiceRegisterer() {
+ return new ServiceRegisterer("isms");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the eUICC controller service.
+ */
+ @NonNull
+ public ServiceRegisterer getEuiccControllerService() {
+ return new ServiceRegisterer("econtroller");
+ }
+
+ @NonNull
+ public ServiceRegisterer getEuiccCardControllerServiceRegisterer() {
+ return new ServiceRegisterer("euicc_card_controller");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the package manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPackageManagerServiceRegisterer() {
+ return new ServiceRegisterer("package");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the permission manager service.
+ */
+ @NonNull
+ public ServiceRegisterer getPermissionManagerServiceRegisterer() {
+ return new ServiceRegisterer("permissionmgr");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the ICC phone book service.
+ */
+ @NonNull
+ public ServiceRegisterer getIccPhoneBookServiceRegisterer() {
+ return new ServiceRegisterer("simphonebook");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the window service.
+ */
+ @NonNull
+ public ServiceRegisterer getWindowServiceRegisterer() {
+ return new ServiceRegisterer(Context.WINDOW_SERVICE);
+ }
}
diff --git a/core/java/android/util/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
index 45056730b08b..348574ed43c7 100644
--- a/core/java/android/util/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -14,13 +14,10 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
import java.util.Objects;
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index a9ddffe7d55c..16f7b398731c 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.IUpdateEngine;
@@ -140,8 +141,43 @@ public class UpdateEngine {
* {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
*/
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
+
+ /**
+ * Error code: there is not enough space on the device to apply the update. User should
+ * be prompted to free up space and re-try the update.
+ *
+ * <p>See {@link UpdateEngine#allocateSpace}.
+ */
+ public static final int NOT_ENOUGH_SPACE = 60;
+
+ /**
+ * Error code: the device is corrupted and no further updates may be applied.
+ *
+ * <p>See {@link UpdateEngine#cleanupAppliedPayload}.
+ */
+ public static final int DEVICE_CORRUPTED = 61;
}
+ /** @hide */
+ @IntDef(value = {
+ ErrorCodeConstants.SUCCESS,
+ ErrorCodeConstants.ERROR,
+ ErrorCodeConstants.FILESYSTEM_COPIER_ERROR,
+ ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+ ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+ ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR,
+ ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+ ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
+ ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+ ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+ ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+ ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+ ErrorCodeConstants.NOT_ENOUGH_SPACE,
+ ErrorCodeConstants.DEVICE_CORRUPTED,
+ })
+ public @interface ErrorCode {}
+
/**
* Status codes for update engine. Values must agree with the ones in
* {@code system/update_engine/client_library/include/update_engine/update_status.h}.
@@ -419,4 +455,138 @@ public class UpdateEngine {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Return value of {@link #allocateSpace.}
+ */
+ public static final class AllocateSpaceResult {
+ private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS;
+ private long mFreeSpaceRequired = 0;
+ private AllocateSpaceResult() {}
+ /**
+ * Error code.
+ *
+ * @return The following error codes:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated
+ * successfully.</li>
+ * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient
+ * space.</li>
+ * <li>Other {@link ErrorCodeConstants} for other errors.</li>
+ * </ul>
+ */
+ @ErrorCode
+ public int errorCode() {
+ return mErrorCode;
+ }
+
+ /**
+ * Estimated total space that needs to be available on the userdata partition to apply the
+ * payload (in bytes).
+ *
+ * <p>
+ * Note that in practice, more space needs to be made available before applying the payload
+ * to keep the device working.
+ *
+ * @return The following values:
+ * <ul>
+ * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li>
+ * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}.
+ * Value is the estimated total space required on userdata partition.</li>
+ * </ul>
+ * @throws IllegalStateException if {@link #errorCode} is not one of the above.
+ *
+ */
+ public long freeSpaceRequired() {
+ if (mErrorCode == ErrorCodeConstants.SUCCESS) {
+ return 0;
+ }
+ if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) {
+ return mFreeSpaceRequired;
+ }
+ throw new IllegalStateException(String.format(
+ "freeSpaceRequired() is not available when error code is %d", mErrorCode));
+ }
+ }
+
+ /**
+ * Initialize partitions for a payload associated with the given payload
+ * metadata {@code payloadMetadataFilename} by preallocating required space.
+ *
+ * <p>This function should be called after payload has been verified after
+ * {@link #verifyPayloadMetadata}. This function does not verify whether
+ * the given payload is applicable or not.
+ *
+ * <p>Implementation of {@code allocateSpace} uses
+ * {@code headerKeyValuePairs} to determine whether space has been allocated
+ * for a different or same payload previously. If space has been allocated
+ * for a different payload before, space will be reallocated for the given
+ * payload. If space has been allocated for the same payload, no actions to
+ * storage devices are taken.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}.
+ * @param headerKeyValuePairs See {@link #applyPayload}.
+ * @return See {@link AllocateSpaceResult}.
+ */
+ @NonNull
+ public AllocateSpaceResult allocateSpace(
+ @NonNull String payloadMetadataFilename,
+ @NonNull String[] headerKeyValuePairs) {
+ AllocateSpaceResult result = new AllocateSpaceResult();
+ try {
+ result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload(
+ payloadMetadataFilename,
+ headerKeyValuePairs);
+ result.mErrorCode = result.mFreeSpaceRequired == 0
+ ? ErrorCodeConstants.SUCCESS
+ : ErrorCodeConstants.NOT_ENOUGH_SPACE;
+ return result;
+ } catch (ServiceSpecificException e) {
+ result.mErrorCode = e.errorCode;
+ result.mFreeSpaceRequired = 0;
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Cleanup files used by the previous update and free up space after the
+ * device has been booted successfully into the new build.
+ *
+ * <p>In particular, this function waits until delta files for snapshots for
+ * Virtual A/B update are merged to OS partitions, then delete these delta
+ * files.
+ *
+ * <p>This function is synchronous and may take a non-trivial amount of
+ * time. Callers should call this function in a background thread.
+ *
+ * <p>This function does not delete payload binaries downloaded for a
+ * non-streaming OTA update.
+ *
+ * @return One of the following:
+ * <ul>
+ * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li>
+ * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred.
+ * The device should be able to recover after a reboot. The function should
+ * be retried after the reboot.</li>
+ * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is
+ * encountered. Device is corrupted, and future updates must not be applied.
+ * The device cannot recover without flashing and factory resets.
+ * </ul>
+ *
+ * @throws ServiceSpecificException if other transient errors has occurred.
+ * A reboot may or may not help resolving the issue.
+ */
+ @ErrorCode
+ public int cleanupAppliedPayload() {
+ try {
+ return mUpdateEngine.cleanupSuccessfulUpdate();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java
index f07294e222e2..7fe7024f25b3 100644
--- a/core/java/android/os/UpdateEngineCallback.java
+++ b/core/java/android/os/UpdateEngineCallback.java
@@ -44,5 +44,6 @@ public abstract class UpdateEngineCallback {
* unsuccessfully. The value of {@code errorCode} will be one of the
* values from {@link UpdateEngine.ErrorCodeConstants}.
*/
- public abstract void onPayloadApplicationComplete(int errorCode);
+ public abstract void onPayloadApplicationComplete(
+ @UpdateEngine.ErrorCode int errorCode);
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 62b8953b158a..3846f894c4c3 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -594,6 +594,8 @@ public class ZygoteProcess {
argsForZygote.add("--mount-external-legacy");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
argsForZygote.add("--mount-external-pass-through");
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ argsForZygote.add("--mount-external-android-writable");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8959fcf7ac18..3ea64f13fe6b 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -31,6 +31,7 @@ import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.BytesLong;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -72,6 +73,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -93,7 +95,6 @@ import com.android.internal.os.AppFuseMount;
import com.android.internal.os.FuseAppLoop;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.os.RoSystemProperties;
-import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import dalvik.system.BlockGuard;
@@ -114,6 +115,7 @@ import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -305,109 +307,85 @@ public class StorageManager {
private final Looper mLooper;
private final AtomicInteger mNextNonce = new AtomicInteger(0);
+ @GuardedBy("mDelegates")
private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
- private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
- Handler.Callback {
- private static final int MSG_STORAGE_STATE_CHANGED = 1;
- private static final int MSG_VOLUME_STATE_CHANGED = 2;
- private static final int MSG_VOLUME_RECORD_CHANGED = 3;
- private static final int MSG_VOLUME_FORGOTTEN = 4;
- private static final int MSG_DISK_SCANNED = 5;
- private static final int MSG_DISK_DESTROYED = 6;
+ private class StorageEventListenerDelegate extends IStorageEventListener.Stub {
+ final Executor mExecutor;
+ final StorageEventListener mListener;
+ final StorageVolumeCallback mCallback;
- final StorageEventListener mCallback;
- final Handler mHandler;
-
- public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
+ public StorageEventListenerDelegate(@NonNull Executor executor,
+ @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback) {
+ mExecutor = executor;
+ mListener = listener;
mCallback = callback;
- mHandler = new Handler(looper, this);
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- final SomeArgs args = (SomeArgs) msg.obj;
- switch (msg.what) {
- case MSG_STORAGE_STATE_CHANGED:
- mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
- (String) args.arg3);
- args.recycle();
- return true;
- case MSG_VOLUME_STATE_CHANGED:
- mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
- args.recycle();
- return true;
- case MSG_VOLUME_RECORD_CHANGED:
- mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
- args.recycle();
- return true;
- case MSG_VOLUME_FORGOTTEN:
- mCallback.onVolumeForgotten((String) args.arg1);
- args.recycle();
- return true;
- case MSG_DISK_SCANNED:
- mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
- args.recycle();
- return true;
- case MSG_DISK_DESTROYED:
- mCallback.onDiskDestroyed((DiskInfo) args.arg1);
- args.recycle();
- return true;
- }
- args.recycle();
- return false;
}
@Override
public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
- // Ignored
+ mExecutor.execute(() -> {
+ mListener.onUsbMassStorageConnectionChanged(connected);
+ });
}
@Override
public void onStorageStateChanged(String path, String oldState, String newState) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = path;
- args.arg2 = oldState;
- args.arg3 = newState;
- mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onStorageStateChanged(path, oldState, newState);
+
+ if (path != null) {
+ for (StorageVolume sv : getStorageVolumes()) {
+ if (Objects.equals(path, sv.getPath())) {
+ mCallback.onStateChanged(sv);
+ }
+ }
+ }
+ });
}
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = vol;
- args.argi2 = oldState;
- args.argi3 = newState;
- mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeStateChanged(vol, oldState, newState);
+
+ final File path = vol.getPathForUser(UserHandle.myUserId());
+ if (path != null) {
+ for (StorageVolume sv : getStorageVolumes()) {
+ if (Objects.equals(path.getAbsolutePath(), sv.getPath())) {
+ mCallback.onStateChanged(sv);
+ }
+ }
+ }
+ });
}
@Override
public void onVolumeRecordChanged(VolumeRecord rec) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = rec;
- mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeRecordChanged(rec);
+ });
}
@Override
public void onVolumeForgotten(String fsUuid) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = fsUuid;
- mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onVolumeForgotten(fsUuid);
+ });
}
@Override
public void onDiskScanned(DiskInfo disk, int volumeCount) {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = disk;
- args.argi2 = volumeCount;
- mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onDiskScanned(disk, volumeCount);
+ });
}
@Override
public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = disk;
- mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
+ mExecutor.execute(() -> {
+ mListener.onDiskDestroyed(disk);
+ });
}
}
@@ -525,8 +503,8 @@ public class StorageManager {
@UnsupportedAppUsage
public void registerListener(StorageEventListener listener) {
synchronized (mDelegates) {
- final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
- mLooper);
+ final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
+ mContext.getMainExecutor(), listener, new StorageVolumeCallback());
try {
mStorageManager.registerListener(delegate);
} catch (RemoteException e) {
@@ -548,7 +526,76 @@ public class StorageManager {
synchronized (mDelegates) {
for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
final StorageEventListenerDelegate delegate = i.next();
- if (delegate.mCallback == listener) {
+ if (delegate.mListener == listener) {
+ try {
+ mStorageManager.unregisterListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ i.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback that delivers {@link StorageVolume} related events.
+ * <p>
+ * For example, this can be used to detect when a volume changes to the
+ * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
+ * states.
+ *
+ * @see StorageManager#registerStorageVolumeCallback
+ * @see StorageManager#unregisterStorageVolumeCallback
+ */
+ public static class StorageVolumeCallback {
+ /**
+ * Called when {@link StorageVolume#getState()} changes, such as
+ * changing to the {@link Environment#MEDIA_MOUNTED} or
+ * {@link Environment#MEDIA_UNMOUNTED} states.
+ * <p>
+ * The given argument is a snapshot in time and can be used to process
+ * events in the order they occurred, or you can call
+ * {@link StorageManager#getStorageVolumes()} to observe the latest
+ * value.
+ */
+ public void onStateChanged(@NonNull StorageVolume volume) { }
+ }
+
+ /**
+ * Registers the given callback to listen for {@link StorageVolume} changes.
+ * <p>
+ * For example, this can be used to detect when a volume changes to the
+ * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
+ * states.
+ *
+ * @see StorageManager#unregisterStorageVolumeCallback
+ */
+ public void registerStorageVolumeCallback(@CallbackExecutor @NonNull Executor executor,
+ @NonNull StorageVolumeCallback callback) {
+ synchronized (mDelegates) {
+ final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
+ executor, new StorageEventListener(), callback);
+ try {
+ mStorageManager.registerListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mDelegates.add(delegate);
+ }
+ }
+
+ /**
+ * Unregisters the given callback from listening for {@link StorageVolume}
+ * changes.
+ *
+ * @see StorageManager#registerStorageVolumeCallback
+ */
+ public void unregisterStorageVolumeCallback(@NonNull StorageVolumeCallback callback) {
+ synchronized (mDelegates) {
+ for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
+ final StorageEventListenerDelegate delegate = i.next();
+ if (delegate.mCallback == callback) {
try {
mStorageManager.unregisterListener(delegate);
} catch (RemoteException e) {
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 2ab226f81bb4..e251f8072b1f 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -18,6 +18,7 @@ package android.os.storage;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -162,9 +163,13 @@ public final class StorageVolume implements Parcelable {
mState = in.readString();
}
- /** {@hide} */
- @UnsupportedAppUsage
- public String getId() {
+ /**
+ * Return an opaque ID that can be used to identify this volume.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull String getId() {
return mId;
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 0a3c333ae7b1..ef8a2860cf4f 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -553,7 +553,9 @@ public final class DocumentsContract {
/**
* Flag indicating that a document is a directory that wants to block itself
* from being selected when the user launches an {@link Intent#ACTION_OPEN_DOCUMENT_TREE}
- * intent. Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
+ * intent. Individual files can still be selected when launched via other intents
+ * like {@link Intent#ACTION_OPEN_DOCUMENT} and {@link Intent#ACTION_GET_CONTENT}.
+ * Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
* <p>
* Note that this flag <em>only</em> applies to the single directory to which it is
* applied. It does <em>not</em> block the user from selecting either a parent or
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bbaf94ad6ea0..07cbcfbb298b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -68,7 +68,6 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
-import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -12459,16 +12458,17 @@ public final class Settings {
/**
* Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
- * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ * value
+ * {@link android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
* <p>
* Type: int (0 for false, 1 for true)
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#ENHANCED_4G_MODE_ENABLED}
* instead.
*/
@Deprecated
public static final String ENHANCED_4G_MODE_ENABLED =
- SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
+ Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -12476,10 +12476,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#VT_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
+ public static final String VT_IMS_ENABLED = Telephony.SimInfo.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -12487,10 +12487,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
+ public static final String WFC_IMS_ENABLED = Telephony.SimInfo.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -12498,10 +12498,10 @@ public final class Settings {
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_MODE} instead.
*/
@Deprecated
- public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
+ public static final String WFC_IMS_MODE = Telephony.SimInfo.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -12509,11 +12509,11 @@ public final class Settings {
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_MODE}
* instead.
*/
@Deprecated
- public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
+ public static final String WFC_IMS_ROAMING_MODE = Telephony.SimInfo.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -12521,12 +12521,12 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_ENABLED}
* instead
*/
@Deprecated
public static final String WFC_IMS_ROAMING_ENABLED =
- SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
+ Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 1d9bdb81a05f..2e7ac3f505fa 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -38,11 +38,13 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
+import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
import android.text.TextUtils;
import android.util.Patterns;
@@ -4980,5 +4982,402 @@ public final class Telephony {
*/
@NonNull
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * TelephonyProvider unique key column name is the subscription id.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+ /**
+ * TelephonyProvider column name for a unique identifier for the subscription within the
+ * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+ * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * TelephonyProvider column name for user SIM_SlOT_INDEX
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_SLOT_INDEX = "sim_id";
+
+ /**
+ * SIM is not inserted
+ */
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * TelephonyProvider column name Subscription-type.
+ * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM
+ * Subscriptions, {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+ * Default value is 0.
+ */
+ public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+ /**
+ * This constant is to designate a subscription as a Local-SIM Subscription.
+ * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on
+ * the device.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+ /**
+ * This constant is to designate a subscription as a Remote-SIM Subscription.
+ * <p>
+ * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+ * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription
+ * can be used for SMS, Voice and data by proxying data through the connected device.
+ * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+ * </p>
+ *
+ * <p>
+ * A Remote-SIM is available only as long the phone stays connected to this device.
+ * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+ * no longer known. All data associated with the subscription, such as stored SMS, call
+ * logs, contacts etc, are removed from this device.
+ * </p>
+ *
+ * <p>
+ * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+ * the phone. The Subscription Id associated with the new subscription is different from
+ * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+ * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM
+ * that was never seen before.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+ /**
+ * TelephonyProvider column name data_enabled_override_rules.
+ * It's a list of rules for overriding data enabled settings. The syntax is
+ * For example, "mms=nonDefault" indicates enabling data for mms in non-default
+ * subscription.
+ * "default=nonDefault&inVoiceCall" indicates enabling data for internet in non-default
+ * subscription and while is in voice call.
+ *
+ * Default value is empty string.
+ */
+ public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+
+ /**
+ * TelephonyProvider column name for user displayed name.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * TelephonyProvider column name for the service provider name for the SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARRIER_NAME = "carrier_name";
+
+ /**
+ * TelephonyProvider column name for source of the user displayed name.
+ * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ /** The name_source is the default, which is from the carrier id. */
+ public static final int NAME_SOURCE_DEFAULT = 0;
+
+ /**
+ * The name_source is from SIM EF_SPN.
+ */
+ public static final int NAME_SOURCE_SIM_SPN = 1;
+
+ /**
+ * The name_source is from user input
+ */
+ public static final int NAME_SOURCE_USER_INPUT = 2;
+
+ /**
+ * The name_source is carrier (carrier app, carrier config, etc.)
+ */
+ public static final int NAME_SOURCE_CARRIER = 3;
+
+ /**
+ * The name_source is from SIM EF_PNN.
+ */
+ public static final int NAME_SOURCE_SIM_PNN = 4;
+
+ /**
+ * TelephonyProvider column name for the color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ /** TelephonyProvider column name for the default color of a SIM {@hide} */
+ public static final int COLOR_DEFAULT = 0;
+
+ /**
+ * TelephonyProvider column name for the phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * TelephonyProvider column name for the number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ /**
+ * TelephonyProvider column name for the default display format of a SIM
+ * @hide
+ */
+ public static final int DISPLAY_NUMBER_DEFAULT = 1;
+
+ /**
+ * TelephonyProvider column name for whether data roaming is enabled.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ /** Indicates that data roaming is enabled for a subscription */
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ /** Indicates that data roaming is disabled for a subscription */
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ /** TelephonyProvider column name for default data roaming setting: disable */
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ /**
+ * TelephonyProvider column name for subscription carrier id.
+ * @see TelephonyManager#getSimCarrierId()
+ * <p>Type: INTEGER (int) </p>
+ */
+ public static final String CARRIER_ID = "carrier_id";
+
+ /**
+ * A comma-separated list of EHPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String EHPLMNS = "ehplmns";
+
+ /**
+ * A comma-separated list of HPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String HPLMNS = "hplmns";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MCC_STRING = "mcc_string";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MNC_STRING = "mnc_string";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MCC = "mcc";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MNC = "mnc";
+
+ /**
+ * TelephonyProvider column name for the iso country code associated with a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ISO_COUNTRY_CODE = "iso_country_code";
+
+ /**
+ * TelephonyProvider column name for the sim provisioning status associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+
+ /** The sim is provisioned {@hide} */
+ public static final int SIM_PROVISIONED = 0;
+
+ /**
+ * TelephonyProvider column name for whether a subscription is embedded (that is, present on
+ * an eSIM).
+ * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+ */
+ public static final String IS_EMBEDDED = "is_embedded";
+
+ /**
+ * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of
+ * the current enabled profile on the card, while for eUICC card it is the EID of the card.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARD_ID = "card_id";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES = "access_rules";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+ * Only present if there are access rules in CarrierConfigs
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+ "access_rules_from_carrier_configs";
+
+ /**
+ * TelephonyProvider column name identifying whether an embedded subscription is on a
+ * removable card. Such subscriptions are marked inaccessible as soon as the current card
+ * is removed. Otherwise, they will remain accessible unless explicitly deleted. Only
+ * present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+ */
+ public static final String IS_REMOVABLE = "is_removable";
+
+ /** TelephonyProvider column name for extreme threat in CB settings */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /** TelephonyProvider column name for severe threat in CB settings */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /** TelephonyProvider column name for amber alert in CB settings */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /** TelephonyProvider column name for emergency alert in CB settings */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /** TelephonyProvider column name for alert sound duration in CB settings */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /** TelephonyProvider column name for alert reminder interval in CB settings */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /** TelephonyProvider column name for enabling vibrate in CB settings */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /** TelephonyProvider column name for enabling alert speech in CB settings */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /** TelephonyProvider column name for ETWS test alert in CB settings */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /** TelephonyProvider column name for enable channel50 alert in CB settings */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /** TelephonyProvider column name for CMAS test alert in CB settings */
+ public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+
+ /** TelephonyProvider column name for Opt out dialog in CB settings */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
+ * TelephonyProvider column name for enable Volte.
+ *
+ * If this setting is not initialized (set to -1) then we use the Carrier Config value
+ * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /** TelephonyProvider column name for enable VT (Video Telephony over IMS) */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /** TelephonyProvider column name for enable Wifi calling */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /** TelephonyProvider column name for Wifi calling mode */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /** TelephonyProvider column name for Wifi calling mode in roaming */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /** TelephonyProvider column name for enable Wifi calling in roaming */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is opportunistic, that is,
+ * whether the network it connects to is limited in functionality or coverage.
+ * For example, CBRS.
+ * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
+ */
+ public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+
+ /**
+ * TelephonyProvider column name for group ID. Subscriptions with same group ID
+ * are considered bundled together, and should behave as a single subscription at
+ * certain scenarios.
+ */
+ public static final String GROUP_UUID = "group_uuid";
+
+ /**
+ * TelephonyProvider column name for group owner. It's the package name who created
+ * the subscription group.
+ */
+ public static final String GROUP_OWNER = "group_owner";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is metered or not, that is,
+ * whether the network it connects to charges for subscription or not. For example, paid
+ * CBRS or unpaid.
+ * @hide
+ */
+ public static final String IS_METERED = "is_metered";
+
+ /**
+ * TelephonyProvider column name for the profile class of a subscription
+ * Only present if {@link #IS_EMBEDDED} is 1.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String PROFILE_CLASS = "profile_class";
+
+ /**
+ * A testing profile can be pre-loaded or downloaded onto
+ * the eUICC and provides connectivity to test equipment
+ * for the purpose of testing the device and the eUICC. It
+ * is not intended to store any operator credentials.
+ */
+ public static final int PROFILE_CLASS_TESTING = 0;
+
+ /**
+ * A provisioning profile is pre-loaded onto the eUICC and
+ * provides connectivity to a mobile network solely for the
+ * purpose of provisioning profiles.
+ */
+ public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+ /**
+ * An operational profile can be pre-loaded or downloaded
+ * onto the eUICC and provides services provided by the
+ * operator.
+ */
+ public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+ /**
+ * The profile class is unset. This occurs when profile class
+ * info is not available. The subscription either has no profile
+ * metadata or the profile metadata did not encode profile class.
+ */
+ public static final int PROFILE_CLASS_UNSET = -1;
+
+ /** Default profile class */
+ public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
+ /**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI = "imsi";
+
+ /** Whether uicc applications is set to be enabled or disabled. By default it's enabled. */
+ public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
}
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d51e4ca6398f..939ae878816a 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -609,10 +609,12 @@ public final class FillResponse implements Parcelable {
"must add at least 1 dataset when using header or footer");
}
- for (final Dataset dataset : mDatasets) {
- if (dataset.getFieldInlinePresentation(0) != null) {
- mSupportsInlineSuggestions = true;
- break;
+ if (mDatasets != null) {
+ for (final Dataset dataset : mDatasets) {
+ if (dataset.getFieldInlinePresentation(0) != null) {
+ mSupportsInlineSuggestions = true;
+ break;
+ }
}
}
diff --git a/core/java/android/telephony/WapPushManagerConnector.java b/core/java/android/telephony/WapPushManagerConnector.java
new file mode 100644
index 000000000000..a9df50685d5d
--- /dev/null
+++ b/core/java/android/telephony/WapPushManagerConnector.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.IWapPushManager;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * APIs for platform to connect to the WAP push manager service.
+ *
+ * <p>To start connection, {@link #bindToWapPushManagerService} should be called.
+ *
+ * <p>Upon completion {@link #unbindWapPushManagerService} should be called to unbind the service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class WapPushManagerConnector {
+ private final Context mContext;
+
+ private volatile WapPushManagerConnection mConnection;
+ private volatile IWapPushManager mWapPushManager;
+ private String mWapPushManagerPackage;
+
+ /**
+ * The {@link android.content.Intent} that must be declared as handled by the
+ * WAP push manager service.
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "com.android.internal.telephony.IWapPushManager";
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"RESULT_"}, value = {
+ RESULT_MESSAGE_HANDLED,
+ RESULT_APP_QUERY_FAILED,
+ RESULT_SIGNATURE_NO_MATCH,
+ RESULT_INVALID_RECEIVER_NAME,
+ RESULT_EXCEPTION_CAUGHT,
+ RESULT_FURTHER_PROCESSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProcessMessageResult{}
+
+ /** {@link #processMessage} return value: Message is handled. */
+ public static final int RESULT_MESSAGE_HANDLED = 0x1;
+ /** {@link #processMessage} return value: Application ID or content type was not found. */
+ public static final int RESULT_APP_QUERY_FAILED = 0x2;
+ /** {@link #processMessage} return value: Receiver application signature check failed. */
+ public static final int RESULT_SIGNATURE_NO_MATCH = 0x4;
+ /** {@link #processMessage} return value: Receiver application was not found. */
+ public static final int RESULT_INVALID_RECEIVER_NAME = 0x8;
+ /** {@link #processMessage} return value: Unknown exception. */
+ public static final int RESULT_EXCEPTION_CAUGHT = 0x10;
+ /** {@link #processMessage} return value: further processing needed. */
+ public static final int RESULT_FURTHER_PROCESSING = 0x8000;
+
+ /** The application package name of the WAP push manager service. */
+ private static final String SERVICE_PACKAGE = "com.android.smspush";
+
+ public WapPushManagerConnector(@NonNull Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Binds to the WAP push manager service. This method should be called exactly once.
+ *
+ * @return {@code true} upon successfully binding to a service, {@code false} otherwise
+ */
+ public boolean bindToWapPushManagerService() {
+ Preconditions.checkState(mConnection == null);
+
+ Intent intent = new Intent(SERVICE_INTERFACE);
+ ComponentName component = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(component);
+ mConnection = new WapPushManagerConnection();
+ if (component != null
+ && mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ mWapPushManagerPackage = component.getPackageName();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the package name of WAP push manager service application connected to,
+ * or {@code null} if not connected.
+ */
+ @Nullable
+ public String getConnectedWapPushManagerServicePackage() {
+ return mWapPushManagerPackage;
+ }
+
+ /**
+ * Processes WAP push message and triggers the {@code intent}.
+ *
+ * @see RESULT_MESSAGE_HANDLED
+ * @see RESULT_APP_QUERY_FAILED
+ * @see RESULT_SIGNATURE_NO_MATCH
+ * @see RESULT_INVALID_RECEIVER_NAME
+ * @see RESULT_EXCEPTION_CAUGHT
+ * @see RESULT_FURTHER_PROCESSING
+ */
+ @ProcessMessageResult
+ public int processMessage(
+ @NonNull String applicationId, @NonNull String contentType, @NonNull Intent intent) {
+ try {
+ return mWapPushManager.processMessage(applicationId, contentType, intent);
+ } catch (NullPointerException | RemoteException e) {
+ return RESULT_EXCEPTION_CAUGHT;
+ }
+ }
+
+ /**
+ * Unbinds the WAP push manager service. This method should be called exactly once.
+ */
+ public void unbindWapPushManagerService() {
+ Preconditions.checkNotNull(mConnection);
+
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+
+ private class WapPushManagerConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Because we have bound to an explicit
+ // service that is running in our own process, we can
+ // cast its IBinder to a concrete class and directly access it.
+ mWapPushManager = IWapPushManager.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mWapPushManager = null;
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ onServiceDisconnected(name);
+ }
+ }
+}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 3f679bba88cd..f324113da925 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -387,6 +387,26 @@ public final class Log {
public static native int println_native(int bufID, int priority, String tag, String msg);
/**
+ * Send a log message to the "radio" log buffer, which can be dumped with
+ * {@code adb logcat -b radio}.
+ *
+ * <p>Only the telephony mainline module should use it.
+ *
+ * <p>Note ART will protect {@code MODULE_LIBRARIES} system APIs from regular app code.
+ *
+ * @param priority Log priority.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param message The message you would like logged.
+ * @hide
+ */
+ // @SystemApi(client= SystemApi.Client.MODULE_LIBRARIES) // TODO Uncomment once http://ag/9956147 is in.
+ public static int logToRadioBuffer(@Level int priority, @Nullable String tag,
+ @Nullable String message) {
+ return println_native(LOG_ID_RADIO, priority, tag, message);
+ }
+
+ /**
* Return the maximum payload the log daemon accepts without truncation.
* @return LOGGER_ENTRY_MAX_PAYLOAD.
*/
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 2223d14ad658..fa994ba76fd7 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -25,6 +25,7 @@ import android.net.Network;
import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.text.TextUtils;
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl
new file mode 100644
index 000000000000..429c3aeba9b3
--- /dev/null
+++ b/core/java/android/view/IDisplayWindowInsetsController.aidl
@@ -0,0 +1,48 @@
+/**
+ * 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.InsetsSourceControl;
+import android.view.InsetsState;
+
+/**
+ * Singular controller of insets to use when there isn't another obvious controller available.
+ * Specifically, this will take over insets control in multi-window.
+ * @hide
+ */
+oneway interface IDisplayWindowInsetsController {
+
+ /**
+ * @see IWindow#insetsChanged
+ */
+ void insetsChanged(in InsetsState insetsState);
+
+ /**
+ * @see IWindow#insetsControlChanged
+ */
+ void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+
+ /**
+ * @see IWindow#showInsets
+ */
+ void showInsets(int types, boolean fromIme);
+
+ /**
+ * @see IWindow#hideInsets
+ */
+ void hideInsets(int types, boolean fromIme);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9496827b1a84..993bdc4d6543 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,6 +35,7 @@ import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowRotationController;
@@ -49,6 +50,7 @@ import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
import android.view.InputEvent;
+import android.view.InsetsState;
import android.view.MagnificationSpec;
import android.view.MotionEvent;
import android.view.InputChannel;
@@ -711,4 +713,16 @@ interface IWindowManager
* @return true if the display was successfully mirrored.
*/
boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl);
+
+ /**
+ * When in multi-window mode, the provided displayWindowInsetsController will control insets
+ * animations.
+ */
+ void setDisplayWindowInsetsController(
+ int displayId, in IDisplayWindowInsetsController displayWindowInsetsController);
+
+ /**
+ * Called when a remote process modifies insets on a display window container.
+ */
+ void modifyDisplayWindowInsets(int displayId, in InsetsState state);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index e3fed3a5dce3..ae1e579da8f6 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -19,10 +19,15 @@ package android.view;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -156,11 +161,10 @@ public class InsetsState implements Parcelable {
&& source.getType() != ITYPE_IME;
boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
&& (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR);
- boolean skipIme = source.getType() == ITYPE_IME
- && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0;
boolean skipLegacyTypes = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && (toPublicType(type) & Type.compatSystemInsets()) != 0;
- if (skipSystemBars || skipIme || skipLegacyTypes || skipNonImeInImeMode) {
+ && (type == ITYPE_STATUS_BAR || type == ITYPE_NAVIGATION_BAR
+ || type == ITYPE_IME);
+ if (skipSystemBars || skipLegacyTypes || skipNonImeInImeMode) {
typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
continue;
}
@@ -175,8 +179,11 @@ public class InsetsState implements Parcelable {
typeMaxInsetsMap, null /* typeSideMap */, null /* typeVisibilityMap */);
}
}
+ final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout);
+ alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
+ ? systemBars() | ime()
+ : systemBars());
}
private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 52ea2b2142ad..17825444a524 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -379,7 +379,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
viewRoot.registerRtFrameCallback(frame -> {
try {
final SurfaceControl.Transaction t = useBLAST ?
@@ -1107,7 +1107,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
Rect position, long frameNumber) {
- if (frameNumber > 0 && ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (frameNumber > 0 && !WindowManagerGlobal.USE_BLAST_ADAPTER) {
final ViewRootImpl viewRoot = getViewRootImpl();
t.deferTransactionUntilSurface(surface, viewRoot.mSurface,
@@ -1125,7 +1125,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
private void setParentSpaceRectangle(Rect position, long frameNumber) {
- final boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ final boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
final ViewRootImpl viewRoot = getViewRootImpl();
final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
mRtTransaction;
@@ -1186,7 +1186,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void positionLost(long frameNumber) {
- boolean useBLAST = ViewRootImpl.USE_BLAST_BUFFERQUEUE;
+ boolean useBLAST = WindowManagerGlobal.USE_BLAST_ADAPTER;
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
@@ -1524,7 +1524,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void invalidate(boolean invalidateCache) {
super.invalidate(invalidateCache);
- if (ViewRootImpl.USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
return;
}
final ViewRootImpl viewRoot = getViewRootImpl();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 522ff9a3bcb5..bf8dc65abe28 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -192,11 +192,6 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean MT_RENDERER_AVAILABLE = true;
/**
- * @hide
- */
- public static final boolean USE_BLAST_BUFFERQUEUE = false;
-
- /**
* If set to 2, the view system will switch from using rectangles retrieved from window to
* dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets
* directly from the full configuration, enabling richer information about the insets state, as
@@ -1312,7 +1307,7 @@ public final class ViewRootImpl implements ViewParent,
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
- if (USE_BLAST_BUFFERQUEUE) {
+ if (WindowManagerGlobal.USE_BLAST_ADAPTER) {
mWindowAttributes.privateFlags =
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
}
@@ -7273,7 +7268,7 @@ public final class ViewRootImpl implements ViewParent,
mPendingStableInsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
if (mSurfaceControl.isValid()) {
- if (USE_BLAST_BUFFERQUEUE == false) {
+ if (!WindowManagerGlobal.USE_BLAST_ADAPTER) {
mSurface.copyFrom(mSurfaceControl);
} else {
mSurface.transferFrom(getOrCreateBLASTSurface(
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index a9cc50f9e65e..9df131de6754 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -27,8 +27,8 @@ import static android.view.WindowInsets.Type.STATUS_BARS;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
import static android.view.WindowInsets.Type.all;
-import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemBars;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -87,6 +87,8 @@ public final class WindowInsets {
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
+ private final int mCompatInsetTypes;
+
/**
* Since new insets may be added in the future that existing apps couldn't
* know about, this fully empty constant shouldn't be made available to apps
@@ -112,7 +114,7 @@ public final class WindowInsets {
boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
- isRound, alwaysConsumeSystemBars, displayCutout);
+ isRound, alwaysConsumeSystemBars, displayCutout, systemBars());
}
/**
@@ -131,7 +133,7 @@ public final class WindowInsets {
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
+ boolean alwaysConsumeSystemBars, DisplayCutout displayCutout, int compatInsetTypes) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -145,6 +147,7 @@ public final class WindowInsets {
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
+ mCompatInsetTypes = compatInsetTypes;
mDisplayCutoutConsumed = displayCutout == null;
mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
@@ -160,7 +163,8 @@ public final class WindowInsets {
this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
- src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
+ src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
+ src.mCompatInsetTypes);
}
private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
@@ -211,7 +215,8 @@ public final class WindowInsets {
/** @hide */
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
- this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
+ this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
+ systemBars());
}
/**
@@ -280,7 +285,7 @@ public final class WindowInsets {
*/
@NonNull
public Insets getSystemWindowInsets() {
- return getInsets(mTypeInsetsMap, compatSystemInsets());
+ return getInsets(mTypeInsetsMap, mCompatInsetTypes);
}
/**
@@ -439,7 +444,8 @@ public final class WindowInsets {
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- null /* displayCutout */);
+ null /* displayCutout */,
+ mCompatInsetTypes);
}
@@ -485,7 +491,8 @@ public final class WindowInsets {
return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
// TODO(b/119190588): replace @code with @link below
@@ -555,7 +562,7 @@ public final class WindowInsets {
*/
@NonNull
public Insets getStableInsets() {
- return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
+ return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
}
/**
@@ -733,7 +740,8 @@ public final class WindowInsets {
public WindowInsets consumeStableInsets() {
return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
- displayCutoutCopyConstructorArgument(this));
+ displayCutoutCopyConstructorArgument(this),
+ mCompatInsetTypes);
}
/**
@@ -817,7 +825,8 @@ public final class WindowInsets {
? null
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
- : mDisplayCutout.inset(left, top, right, bottom));
+ : mDisplayCutout.inset(left, top, right, bottom),
+ mCompatInsetTypes);
}
@Override
@@ -1134,7 +1143,8 @@ public final class WindowInsets {
public WindowInsets build() {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
+ mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout,
+ systemBars());
}
}
@@ -1271,15 +1281,6 @@ public final class WindowInsets {
}
/**
- * @return Inset types representing the list of bars that traditionally were denoted as
- * system insets.
- * @hide
- */
- static @InsetsType int compatSystemInsets() {
- return STATUS_BARS | NAVIGATION_BARS | IME;
- }
-
- /**
* @return All inset types combined.
*
* TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 95780023563d..7d5564e1c8be 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -57,6 +57,12 @@ public final class WindowManagerGlobal {
private static final String TAG = "WindowManager";
/**
+ * This flag controls whether ViewRootImpl will utilize the Blast Adapter
+ * to send buffer updates to SurfaceFlinger
+ */
+ public static final boolean USE_BLAST_ADAPTER = false;
+
+ /**
* The user is navigating with keys (not the touch screen), so
* navigational focus should be shown.
*/
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
new file mode 100644
index 000000000000..0b937fad7df1
--- /dev/null
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -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 com.android.internal.compat;
+
+import android.os.Build;
+
+/**
+ * Platform private class for determining the type of Android build installed.
+ *
+ */
+public class AndroidBuildClassifier {
+
+ public boolean isDebuggableBuild() {
+ return Build.IS_DEBUGGABLE;
+ }
+
+ public boolean isFinalBuild() {
+ return "REL".equals(Build.VERSION.CODENAME);
+ }
+}
diff --git a/core/java/com/android/internal/compat/IOverrideValidator.aidl b/core/java/com/android/internal/compat/IOverrideValidator.aidl
new file mode 100644
index 000000000000..add4708863aa
--- /dev/null
+++ b/core/java/com/android/internal/compat/IOverrideValidator.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Platform private API for determining whether a changeId can be overridden.
+ *
+ * {@hide}
+ */
+interface IOverrideValidator
+{
+ /**
+ * Validation function.
+ * @param changeId id of the change to be toggled on or off.
+ * @param packageName package of the app for which the change should be overridden.
+ * @return {@link OverrideAllowedState} specifying whether the change can be overridden for
+ * the given package or a reason why not.
+ */
+ OverrideAllowedState getOverrideAllowedState(long changeId, String packageName);
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 7dcb12c9e72b..4c203d394759 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -17,6 +17,7 @@
package com.android.internal.compat;
import android.content.pm.ApplicationInfo;
+import com.android.internal.compat.IOverrideValidator;
import java.util.Map;
parcelable CompatibilityChangeConfig;
@@ -195,4 +196,9 @@ interface IPlatformCompat
* @return An array of {@link CompatChangeInfo} known to the service.
*/
CompatibilityChangeInfo[] listAllChanges();
+
+ /**
+ * Get an instance that can determine whether a changeid can be overridden for a package name.
+ */
+ IOverrideValidator getOverrideValidator();
}
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.aidl b/core/java/com/android/internal/compat/OverrideAllowedState.aidl
new file mode 100644
index 000000000000..10ceac786841
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.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 com.android.internal.compat;
+
+parcelable OverrideAllowedState; \ No newline at end of file
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
new file mode 100644
index 000000000000..56216c251070
--- /dev/null
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class contains all the possible override allowed states.
+ */
+public final class OverrideAllowedState implements Parcelable {
+ @IntDef({
+ ALLOWED,
+ DISABLED_NOT_DEBUGGABLE,
+ DISABLED_NON_TARGET_SDK,
+ DISABLED_TARGET_SDK_TOO_HIGH,
+ PACKAGE_DOES_NOT_EXIST
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
+ /**
+ * Change can be overridden.
+ */
+ public static final int ALLOWED = 0;
+ /**
+ * Change cannot be overridden, due to the app not being debuggable.
+ */
+ public static final int DISABLED_NOT_DEBUGGABLE = 1;
+ /**
+ * Change cannot be overridden, due to the build being non-debuggable and the change being
+ * non-targetSdk.
+ */
+ public static final int DISABLED_NON_TARGET_SDK = 2;
+ /**
+ * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk.
+ */
+ public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3;
+ /**
+ * Package does not exist.
+ */
+ public static final int PACKAGE_DOES_NOT_EXIST = 4;
+
+ @State
+ public final int state;
+ public final int appTargetSdk;
+ public final int changeIdTargetSdk;
+
+ private OverrideAllowedState(Parcel parcel) {
+ state = parcel.readInt();
+ appTargetSdk = parcel.readInt();
+ changeIdTargetSdk = parcel.readInt();
+ }
+
+ public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) {
+ this.state = state;
+ this.appTargetSdk = appTargetSdk;
+ this.changeIdTargetSdk = changeIdTargetSdk;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(state);
+ out.writeInt(appTargetSdk);
+ out.writeInt(changeIdTargetSdk);
+ }
+
+ /**
+ * Enforces the policy for overriding compat changes.
+ *
+ * @param changeId the change id that was attempted to be overridden.
+ * @param packageName the package for which the attempt was made.
+ * @throws SecurityException if the policy forbids this operation.
+ */
+ public void enforce(long changeId, String packageName)
+ throws SecurityException {
+ switch (state) {
+ case ALLOWED:
+ return;
+ case DISABLED_NOT_DEBUGGABLE:
+ throw new SecurityException(
+ "Cannot override a change on a non-debuggable app and user build.");
+ case DISABLED_NON_TARGET_SDK:
+ throw new SecurityException(
+ "Cannot override a default enabled/disabled change on a user build.");
+ case DISABLED_TARGET_SDK_TOO_HIGH:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is "
+ + "above the change's targetSdk threshold (%4$d)",
+ changeId, packageName, appTargetSdk, changeIdTargetSdk));
+ case PACKAGE_DOES_NOT_EXIST:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the package does not exist, and "
+ + "the change is targetSdk gated.",
+ changeId, packageName));
+ }
+ }
+
+ public static final @NonNull
+ Parcelable.Creator<OverrideAllowedState> CREATOR =
+ new Parcelable.Creator<OverrideAllowedState>() {
+ public OverrideAllowedState createFromParcel(Parcel parcel) {
+ OverrideAllowedState info = new OverrideAllowedState(parcel);
+ return info;
+ }
+
+ public OverrideAllowedState[] newArray(int size) {
+ return new OverrideAllowedState[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof OverrideAllowedState)) {
+ return false;
+ }
+ OverrideAllowedState otherState = (OverrideAllowedState) obj;
+ return state == otherState.state
+ && appTargetSdk == otherState.appTargetSdk
+ && changeIdTargetSdk == otherState.changeIdTargetSdk;
+ }
+}
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index b250578c8454..9f15d8991fa7 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -75,6 +75,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
private static final boolean DEBUG = false;
private static final String LOG_TAG = AndroidFuture.class.getSimpleName();
+ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
private final @NonNull Object mLock = new Object();
@GuardedBy("mLock")
@@ -95,15 +96,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
// Done
if (in.readBoolean()) {
// Failed
- try {
- in.readException();
- } catch (Throwable e) {
- completeExceptionally(e);
- }
- if (!isCompletedExceptionally()) {
- throw new IllegalStateException(
- "Error unparceling AndroidFuture: exception expected");
- }
+ completeExceptionally(unparcelException(in));
} else {
// Success
complete((T) in.readValue(null));
@@ -512,14 +505,9 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
T result;
try {
result = get();
- } catch (Exception t) {
- // Exceptions coming out of get() are wrapped in ExecutionException, which is not
- // handled by Parcel.
- if (t instanceof ExecutionException && t.getCause() instanceof Exception) {
- t = (Exception) t.getCause();
- }
+ } catch (Throwable t) {
dest.writeBoolean(true);
- dest.writeException(t);
+ parcelException(dest, unwrapExecutionException(t));
return;
}
dest.writeBoolean(false);
@@ -528,22 +516,76 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
dest.writeStrongBinder(new IAndroidFuture.Stub() {
@Override
public void complete(AndroidFuture resultContainer) {
+ boolean changed;
try {
- AndroidFuture.this.complete((T) resultContainer.get());
+ changed = AndroidFuture.this.complete((T) resultContainer.get());
} catch (Throwable t) {
- // If resultContainer was completed exceptionally, get() wraps the
- // underlying exception in an ExecutionException. Unwrap it now to avoid
- // double-layering ExecutionExceptions.
- if (t instanceof ExecutionException && t.getCause() != null) {
- t = t.getCause();
- }
- completeExceptionally(t);
+ changed = completeExceptionally(unwrapExecutionException(t));
+ }
+ if (!changed) {
+ Log.w(LOG_TAG, "Remote result " + resultContainer
+ + " ignored, as local future is already completed: "
+ + AndroidFuture.this);
}
}
}.asBinder());
}
}
+ /**
+ * Exceptions coming out of {@link #get} are wrapped in {@link ExecutionException}
+ */
+ Throwable unwrapExecutionException(Throwable t) {
+ return t instanceof ExecutionException
+ ? t.getCause()
+ : t;
+ }
+
+ /**
+ * Alternative to {@link Parcel#writeException} that stores the stack trace, in a
+ * way consistent with the binder IPC exception propagation behavior.
+ */
+ private static void parcelException(Parcel p, @Nullable Throwable t) {
+ p.writeBoolean(t == null);
+ if (t == null) {
+ return;
+ }
+
+ p.writeInt(Parcel.getExceptionCode(t));
+ p.writeString(t.getClass().getName());
+ p.writeString(t.getMessage());
+ p.writeStackTrace(t);
+ parcelException(p, t.getCause());
+ }
+
+ /**
+ * @see #parcelException
+ */
+ private static @Nullable Throwable unparcelException(Parcel p) {
+ if (p.readBoolean()) {
+ return null;
+ }
+
+ int exCode = p.readInt();
+ String cls = p.readString();
+ String msg = p.readString();
+ String stackTrace = p.readInt() > 0 ? p.readString() : "\t<stack trace unavailable>";
+ msg += "\n" + stackTrace;
+
+ Exception ex = p.createExceptionOrNull(exCode, msg);
+ if (ex == null) {
+ ex = new RuntimeException(cls + ": " + msg);
+ }
+ ex.setStackTrace(EMPTY_STACK_TRACE);
+
+ Throwable cause = unparcelException(p);
+ if (cause != null) {
+ ex.initCause(ex);
+ }
+
+ return ex;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2248b8853f8c..f0a346ab25fd 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -145,6 +145,11 @@ public final class Zygote {
/** The lower file system should be bind mounted directly on external storage */
public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
+ /** Use the regular scoped storage filesystem, but Android/ should be writable.
+ * Used to support the applications hosting DownloadManager and the MTP server.
+ */
+ public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE;
+
/** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index d3499541a3a3..37f570bba238 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -376,6 +376,8 @@ class ZygoteArguments {
mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
} else if (arg.equals("--mount-external-pass-through")) {
mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
+ } else if (arg.equals("--mount-external-android-writable")) {
+ mMountExternal = Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
} else if (arg.equals("--query-abi-list")) {
mAbiListQuery = true;
} else if (arg.equals("--get-pid")) {
diff --git a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl b/core/java/com/android/internal/telephony/IWapPushManager.aidl
index 1c3df65336f8..9f6851b8c254 100644
--- a/telephony/java/com/android/internal/telephony/IWapPushManager.aidl
+++ b/core/java/com/android/internal/telephony/IWapPushManager.aidl
@@ -18,6 +18,7 @@ package com.android.internal.telephony;
import android.content.Intent;
+/** @hide */
interface IWapPushManager {
/**
* Processes WAP push message and triggers the receiver application registered
@@ -26,11 +27,10 @@ interface IWapPushManager {
int processMessage(String app_id, String content_type, in Intent intent);
/**
- * Add receiver application into the application ID table.
- * Returns true if inserting the information is successfull. Inserting the duplicated
+ * Adds receiver application into the application ID table.
+ * Returns true if inserting the information is successful. Inserting duplicated
* record in the application ID table is not allowed. Use update/delete method.
*/
- @UnsupportedAppUsage
boolean addPackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
@@ -39,17 +39,14 @@ interface IWapPushManager {
* Updates receiver application that is last added.
* Returns true if updating the information is successfull.
*/
- @UnsupportedAppUsage
boolean updatePackage(String x_app_id, String content_type,
String package_name, String class_name,
int app_type, boolean need_signature, boolean further_processing);
/**
- * Delites receiver application information.
+ * Deletes receiver application information.
* Returns true if deleting is successfull.
*/
- @UnsupportedAppUsage
boolean deletePackage(String x_app_id, String content_type,
- String package_name, String class_name);
+ String package_name, String class_name);
}
-
diff --git a/core/java/com/android/internal/telephony/WapPushManagerParams.java b/core/java/com/android/internal/telephony/WapPushManagerParams.java
new file mode 100644
index 000000000000..eafb8f1b423f
--- /dev/null
+++ b/core/java/com/android/internal/telephony/WapPushManagerParams.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.WapPushManagerConnector;
+
+/**
+ * WapPushManager constant value definitions.
+ * @hide
+ */
+public class WapPushManagerParams {
+ /**
+ * Application type activity
+ */
+ public static final int APP_TYPE_ACTIVITY = 0;
+
+ /**
+ * Application type service
+ */
+ public static final int APP_TYPE_SERVICE = 1;
+
+ /**
+ * Process Message return value
+ * Message is handled
+ */
+ public static final int MESSAGE_HANDLED = WapPushManagerConnector.RESULT_MESSAGE_HANDLED;
+
+ /**
+ * Process Message return value
+ * Application ID or content type was not found in the application ID table
+ */
+ public static final int APP_QUERY_FAILED = WapPushManagerConnector.RESULT_APP_QUERY_FAILED;
+
+ /**
+ * Process Message return value
+ * Receiver application signature check failed
+ */
+ public static final int SIGNATURE_NO_MATCH = WapPushManagerConnector.RESULT_SIGNATURE_NO_MATCH;
+
+ /**
+ * Process Message return value
+ * Receiver application was not found
+ */
+ public static final int INVALID_RECEIVER_NAME =
+ WapPushManagerConnector.RESULT_INVALID_RECEIVER_NAME;
+
+ /**
+ * Process Message return value
+ * Unknown exception
+ */
+ public static final int EXCEPTION_CAUGHT = WapPushManagerConnector.RESULT_EXCEPTION_CAUGHT;
+
+ /**
+ * Process Message return value
+ * Need further processing after WapPushManager message processing
+ */
+ public static final int FURTHER_PROCESSING = WapPushManagerConnector.RESULT_FURTHER_PROCESSING;
+}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d17d0a4ebbe2..5039213954d7 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -319,7 +319,8 @@ enum MountExternalKind {
MOUNT_EXTERNAL_INSTALLER = 5,
MOUNT_EXTERNAL_FULL = 6,
MOUNT_EXTERNAL_PASS_THROUGH = 7,
- MOUNT_EXTERNAL_COUNT = 8
+ MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
+ MOUNT_EXTERNAL_COUNT = 9
};
// The order of entries here must be kept in sync with MountExternalKind enum values.
@@ -331,6 +332,8 @@ static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorage
"/mnt/runtime/write", // MOUNT_EXTERNAL_LEGACY
"/mnt/runtime/write", // MOUNT_EXTERNAL_INSTALLER
"/mnt/runtime/full", // MOUNT_EXTERNAL_FULL
+ "/mnt/runtime/full", // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE)
+ "/mnt/runtime/full", // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE)
};
// Must match values in com.android.internal.os.Zygote.
@@ -755,12 +758,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
if (isFuse) {
- if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH || mount_mode ==
- MOUNT_EXTERNAL_INSTALLER || mount_mode == MOUNT_EXTERNAL_FULL) {
- // For now, MediaProvider, installers and "full" get the pass_through mount
- // view, which is currently identical to the sdcardfs write view.
- //
- // TODO(b/146189163): scope down MOUNT_EXTERNAL_INSTALLER
+ if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
BindMount(pass_through_source, "/storage", fail_fn);
} else {
BindMount(user_source, "/storage", fail_fn);
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 5624f457a9b2..082a2892e34b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,27 +33,27 @@
// Static whitelist of open paths that the zygote is allowed to keep open.
static const char* kPathWhitelist[] = {
- "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
- "/apex/com.android.conscrypt/javalib/conscrypt.jar",
- "/apex/com.android.ipsec/javalib/ike.jar",
- "/apex/com.android.media/javalib/updatable-media.jar",
- "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
- "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
- "/apex/com.android.sdkext/javalib/framework-sdkext.jar",
- "/apex/com.android.wifi/javalib/framework-wifi.jar",
- "/apex/com.android.tethering/javalib/framework-tethering.jar",
- "/dev/null",
- "/dev/socket/zygote",
- "/dev/socket/zygote_secondary",
- "/dev/socket/usap_pool_primary",
- "/dev/socket/usap_pool_secondary",
- "/dev/socket/webview_zygote",
- "/dev/socket/heapprofd",
- "/sys/kernel/debug/tracing/trace_marker",
- "/system/framework/framework-res.apk",
- "/dev/urandom",
- "/dev/ion",
- "/dev/dri/renderD129", // Fixes b/31172436
+ "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
+ "/apex/com.android.conscrypt/javalib/conscrypt.jar",
+ "/apex/com.android.ipsec/javalib/ike.jar",
+ "/apex/com.android.media/javalib/updatable-media.jar",
+ "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
+ "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
+ "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar",
+ "/apex/com.android.wifi/javalib/framework-wifi.jar",
+ "/apex/com.android.tethering/javalib/framework-tethering.jar",
+ "/dev/null",
+ "/dev/socket/zygote",
+ "/dev/socket/zygote_secondary",
+ "/dev/socket/usap_pool_primary",
+ "/dev/socket/usap_pool_secondary",
+ "/dev/socket/webview_zygote",
+ "/dev/socket/heapprofd",
+ "/sys/kernel/debug/tracing/trace_marker",
+ "/system/framework/framework-res.apk",
+ "/dev/urandom",
+ "/dev/ion",
+ "/dev/dri/renderD129", // Fixes b/31172436
};
static const char kFdPath[] = "/proc/self/fd";
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
index 70627edf2cb3..c6925f448a58 100644
--- a/core/proto/android/server/animationadapter.proto
+++ b/core/proto/android/server/animationadapter.proto
@@ -50,6 +50,7 @@ message AnimationSpecProto {
optional WindowAnimationSpecProto window = 1;
optional MoveAnimationSpecProto move = 2;
optional AlphaAnimationSpecProto alpha = 3;
+ optional RotationAnimationSpecProto rotate = 4;
}
/* represents WindowAnimationSpec */
@@ -76,3 +77,12 @@ message AlphaAnimationSpecProto {
optional float to = 2;
optional int64 duration_ms = 3;
}
+
+/* represents RotationAnimationSpec */
+message RotationAnimationSpecProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional float start_luma = 1;
+ optional float end_luma = 2;
+ optional int64 duration_ms = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31faff6bd314..ea70dcf28e69 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -456,7 +456,6 @@
<protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
<protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" />
- <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" />
<protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" />
<protected-broadcast android:name="android.intent.action.USER_UNLOCKED" />
diff --git a/core/res/res/anim/screen_rotate_0_enter.xml b/core/res/res/anim/screen_rotate_0_enter.xml
index 93cf3652d185..629be7ea2d30 100644
--- a/core/res/res/anim/screen_rotate_0_enter.xml
+++ b/core/res/res/anim/screen_rotate_0_enter.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml
index 37d5a4115621..fa046a036855 100644
--- a/core/res/res/anim/screen_rotate_0_exit.xml
+++ b/core/res/res/anim/screen_rotate_0_exit.xml
@@ -1,22 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2010, 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.
-*/
--->
+ ~ 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.
+ -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_0_frame.xml b/core/res/res/anim/screen_rotate_0_frame.xml
deleted file mode 100644
index 5ea9bf8205e3..000000000000
--- a/core/res/res/anim/screen_rotate_0_frame.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_shortAnimTime" />
-</set>
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 688a8d5bb2aa..889a615e07f4 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="180" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set>
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index 58a1868bd398..766fcfae1f91 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -18,11 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-180"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_180" />
</set> \ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_alpha.xml b/core/res/res/anim/screen_rotate_alpha.xml
index c49ef9cafd39..2cac982e24b4 100644
--- a/core/res/res/anim/screen_rotate_alpha.xml
+++ b/core/res/res/anim/screen_rotate_alpha.xml
@@ -20,8 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/decelerate_quint"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index b16d5fc761ee..87fd25ea4603 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -18,19 +18,17 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase anim
+ android:shareInterpolator="false">
<rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="-90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index 0927dd30ceb3..c3aee14dc235 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 86a8d24cbbcc..8849db421e75 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -18,19 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <rotate android:fromDegrees="90" android:toDegrees="0"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:interpolator="@interpolator/screen_rotation_alpha_in"
+ android:startOffset="@android:integer/config_screen_rotation_fade_in_delay"
+ android:duration="@android:integer/config_screen_rotation_fade_in" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index fd786f9afce0..de84c3bd08fc 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -18,26 +18,16 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
- <!-- Version for two-phase animation
+ android:shareInterpolator="false">
<rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_longAnimTime" />
- -->
- <scale android:fromXScale="100%" android:toXScale="100%p"
- android:fromYScale="100%" android:toYScale="100%p"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
- <rotate android:fromDegrees="0" android:toDegrees="-90"
- android:pivotX="50%" android:pivotY="50%"
- android:interpolator="@interpolator/decelerate_quint"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="@android:integer/config_mediumAnimTime" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="@android:integer/config_screen_rotation_total_90" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/screen_rotation_alpha_out"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_screen_rotation_fade_out" />
</set>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_in.xml b/core/res/res/interpolator/screen_rotation_alpha_in.xml
new file mode 100644
index 000000000000..9c566a7c8f23
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_in.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.15"
+ android:controlY1="0.45"
+ android:controlX2="0.33"
+ android:controlY2="1"/>
diff --git a/core/res/res/interpolator/screen_rotation_alpha_out.xml b/core/res/res/interpolator/screen_rotation_alpha_out.xml
new file mode 100644
index 000000000000..73a37d4f1aa5
--- /dev/null
+++ b/core/res/res/interpolator/screen_rotation_alpha_out.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.57"
+ android:controlY1="0"
+ android:controlX2="0.71"
+ android:controlY2=".43"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6691d4c5955b..245aed1484f7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -147,6 +147,24 @@
<integer name="config_activityShortDur">150</integer>
<integer name="config_activityDefaultDur">220</integer>
+ <!-- Fade out time for screen rotation -->
+ <integer name="config_screen_rotation_fade_out">116</integer>
+
+ <!-- Fade in time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in">233</integer>
+
+ <!-- Fade in delay time for screen rotation -->
+ <integer name="config_screen_rotation_fade_in_delay">100</integer>
+
+ <!-- Total time for 90 degree screen rotation animations -->
+ <integer name="config_screen_rotation_total_90">333</integer>
+
+ <!-- Total time for 180 degree screen rotation animation -->
+ <integer name="config_screen_rotation_total_180">433</integer>
+
+ <!-- Total time for the rotation background color transition -->
+ <integer name="config_screen_rotation_color_transition">200</integer>
+
<!-- The duration (in milliseconds) of the tooltip show/hide animations. -->
<integer name="config_tooltipAnimTime">150</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01bd510dcf27..cdbf14bf969a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1805,7 +1805,6 @@
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
<java-symbol type="anim" name="screen_rotate_0_exit" />
- <java-symbol type="anim" name="screen_rotate_0_frame" />
<java-symbol type="anim" name="screen_rotate_180_enter" />
<java-symbol type="anim" name="screen_rotate_180_exit" />
<java-symbol type="anim" name="screen_rotate_180_frame" />
@@ -1981,6 +1980,7 @@
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="integer" name="config_brightness_ramp_rate_fast" />
<java-symbol type="integer" name="config_brightness_ramp_rate_slow" />
+ <java-symbol type="integer" name="config_screen_rotation_color_transition" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
<java-symbol type="layout" name="safe_mode" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 2989df83866c..5d42915fc82b 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -268,7 +268,7 @@ public class BandwidthTest extends InstrumentationTestCase {
File snd_stat = new File (root_filepath + "tcp_snd");
int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
+ stats.addEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
NetworkStats.TAG_NONE, rx, 0, tx, 0, 0);
return stats;
}
diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
index 707d7b30e09b..239f971664e9 100644
--- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
+++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
@@ -54,7 +54,7 @@ public class NetworkStatsBenchmark {
recycle.txBytes = 150000;
recycle.txPackets = 1500;
recycle.operations = 0;
- mNetworkStats.addValues(recycle);
+ mNetworkStats.addEntry(recycle);
if (recycle.set == 1) {
uid++;
}
@@ -70,7 +70,7 @@ public class NetworkStatsBenchmark {
recycle.txBytes = 180000 * mSize;
recycle.txPackets = 1200 * mSize;
recycle.operations = 0;
- mNetworkStats.addValues(recycle);
+ mNetworkStats.addEntry(recycle);
}
}
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index de6f8f7231fa..750ffa1c9a54 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
index 9b3d0c9eaff6..b88c36f20bc6 100644
--- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index bee270e5f5c9..ba29a97b55ab 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -22,7 +22,7 @@ import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcel
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/os/TimestampedValueTest.java
index 6fc2400316c2..f36d9e6b1eff 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/os/TimestampedValueTest.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.util;
+package android.os;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
-import android.os.Parcel;
-
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 60620881b6f2..fa2ffccaaa63 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -23,6 +23,7 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static org.junit.Assert.assertEquals;
@@ -116,14 +117,18 @@ public class InsetsStateTest {
@Test
public void testCalculateInsets_imeIgnoredWithoutAdjustResize() {
- mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
- mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
- mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
- mState.getSource(ITYPE_IME).setVisible(true);
- WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
- DisplayCutout.NO_CUTOUT, null, null, 0, null);
- assertEquals(0, insets.getSystemWindowInsetBottom());
- assertTrue(insets.isVisible(ime()));
+ try (final InsetsModeSession session =
+ new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+ DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_NOTHING, null);
+ assertEquals(0, insets.getSystemWindowInsetBottom());
+ assertEquals(100, insets.getInsets(ime()).bottom);
+ assertTrue(insets.isVisible(ime()));
+ }
}
@Test
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 8c7b28af2e78..e5a4f6d5b3be 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -63,7 +63,8 @@ public class WindowInsetsTest {
b.setInsets(navigationBars(), Insets.of(0, 0, 0, 100));
b.setInsets(ime(), Insets.of(0, 0, 0, 300));
WindowInsets insets = b.build();
- assertEquals(300, insets.getSystemWindowInsets().bottom);
+ assertEquals(100, insets.getSystemWindowInsets().bottom);
+ assertEquals(300, insets.getInsets(ime()).bottom);
}
// TODO: Move this to CTS once API made public
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
index ffc925ff82cd..f108eb8aeb0b 100644
--- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -121,7 +121,12 @@ public class AndroidFutureTest {
AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
ExecutionException executionException =
expectThrows(ExecutionException.class, future2::get);
- assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
+
+ Throwable cause = executionException.getCause();
+ String msg = cause.getMessage();
+ assertThat(cause).isInstanceOf(UnsupportedOperationException.class);
+ assertThat(msg).contains(getClass().getName());
+ assertThat(msg).contains("testWriteToParcel_Exception");
}
@Test
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index e53f3db08538..6d4a0c6421d9 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -52,8 +52,8 @@ void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
}
-void DeviceInfo::onDisplayConfigChanged() {
- updateDisplayInfo();
+void DeviceInfo::onRefreshRateChanged(int64_t vsyncPeriod) {
+ mVsyncPeriod = vsyncPeriod;
}
void DeviceInfo::updateDisplayInfo() {
@@ -113,10 +113,11 @@ void DeviceInfo::updateDisplayInfo() {
ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex];
status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status);
+
mWidth = ADisplayConfig_getWidth(mCurrentConfig);
mHeight = ADisplayConfig_getHeight(mCurrentConfig);
mDensity = ADisplayConfig_getDensity(mCurrentConfig);
- mRefreshRate = ADisplayConfig_getFps(mCurrentConfig);
+ mVsyncPeriod = static_cast<int64_t>(1000000000 / ADisplayConfig_getFps(mCurrentConfig));
mCompositorOffset = ADisplayConfig_getCompositorOffsetNanos(mCurrentConfig);
mAppOffset = ADisplayConfig_getAppVsyncOffsetNanos(mCurrentConfig);
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index a4207460883e..16a22f4706f5 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -37,7 +37,7 @@ public:
static int32_t getWidth() { return get()->mWidth; }
static int32_t getHeight() { return get()->mHeight; }
static float getDensity() { return get()->mDensity; }
- static float getRefreshRate() { return get()->mRefreshRate; }
+ static int64_t getVsyncPeriod() { return get()->mVsyncPeriod; }
static int64_t getCompositorOffset() { return get()->mCompositorOffset; }
static int64_t getAppOffset() { return get()->mAppOffset; }
@@ -47,7 +47,8 @@ public:
sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
SkColorType getWideColorType() const { return mWideColorType; }
- void onDisplayConfigChanged();
+ // This method should be called whenever the display refresh rate changes.
+ void onRefreshRateChanged(int64_t vsyncPeriod);
private:
friend class renderthread::RenderThread;
@@ -68,7 +69,7 @@ private:
int32_t mWidth = 1080;
int32_t mHeight = 1920;
float mDensity = 2.0;
- float mRefreshRate = 60.0;
+ int64_t mVsyncPeriod = 16666666;
int64_t mCompositorOffset = 0;
int64_t mAppOffset = 0;
};
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 10e7160e7069..d25fc4b0b03e 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -81,7 +81,7 @@ static FrameInfoIndex sFrameStart = FrameInfoIndex::IntendedVsync;
JankTracker::JankTracker(ProfileDataContainer* globalData) {
mGlobalData = globalData;
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
nsecs_t sfOffset = DeviceInfo::getCompositorOffset();
nsecs_t offsetDelta = sfOffset - DeviceInfo::getAppOffset();
// There are two different offset cases. If the offsetDelta is positive
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index f4149b9b4d7d..84549e8ce6e4 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -152,7 +152,9 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorS
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
- const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
+ // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
+ const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
+ const size_t rowBytes = info.bytesPerPixel() * bufferStride;
return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a446858ca565..d78f641d45b9 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -34,7 +34,6 @@
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>
-#include <gui/DisplayEventReceiver.h>
#include <sys/resource.h>
#include <utils/Condition.h>
#include <utils/Log.h>
@@ -45,53 +44,43 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-// Number of events to read at a time from the DisplayEventReceiver pipe.
-// The value should be large enough that we can quickly drain the pipe
-// using just a few large reads.
-static const size_t EVENT_BUFFER_SIZE = 100;
-
static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
-class DisplayEventReceiverWrapper : public VsyncSource {
+void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ rt->mVsyncRequested = false;
+ if (rt->timeLord().vsyncReceived(frameTimeNanos) && !rt->mFrameCallbackTaskPending) {
+ ATRACE_NAME("queue mFrameCallbackTask");
+ rt->mFrameCallbackTaskPending = true;
+ nsecs_t runAt = (frameTimeNanos + rt->mDispatchFrameDelay);
+ rt->queue().postAt(runAt, [=]() { rt->dispatchFrameCallbacks(); });
+ }
+}
+
+void RenderThread::refreshRateCallback(int64_t vsyncPeriod, void* data) {
+ ATRACE_NAME("refreshRateCallback");
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ DeviceInfo::get()->onRefreshRateChanged(vsyncPeriod);
+ rt->setupFrameInterval();
+}
+
+class ChoreographerSource : public VsyncSource {
public:
- DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver,
- const std::function<void()>& onDisplayConfigChanged)
- : mDisplayEventReceiver(std::move(receiver))
- , mOnDisplayConfigChanged(onDisplayConfigChanged) {}
+ ChoreographerSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- status_t status = mDisplayEventReceiver->requestNextVsync();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
+ AChoreographer_postFrameCallback64(mRenderThread->mChoreographer,
+ RenderThread::frameCallback, mRenderThread);
}
- virtual nsecs_t latestVsyncEvent() override {
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- nsecs_t latest = 0;
- ssize_t n;
- while ((n = mDisplayEventReceiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- for (ssize_t i = 0; i < n; i++) {
- const DisplayEventReceiver::Event& ev = buf[i];
- switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- latest = ev.header.timestamp;
- break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- mOnDisplayConfigChanged();
- break;
- }
- }
- }
- if (n < 0) {
- ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
- }
- return latest;
+ virtual void drainPendingEvents() override {
+ AChoreographer_handlePendingEvents(mRenderThread->mChoreographer, mRenderThread);
}
private:
- std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
- std::function<void()> mOnDisplayConfigChanged;
+ RenderThread* mRenderThread;
};
class DummyVsyncSource : public VsyncSource {
@@ -99,11 +88,14 @@ public:
DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
- mRenderThread->queue().postDelayed(16_ms,
- [this]() { mRenderThread->drainDisplayEventQueue(); });
+ mRenderThread->queue().postDelayed(16_ms, [this]() {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ });
}
- virtual nsecs_t latestVsyncEvent() override { return systemTime(SYSTEM_TIME_MONOTONIC); }
+ virtual void drainPendingEvents() override {
+ RenderThread::frameCallback(systemTime(SYSTEM_TIME_MONOTONIC), mRenderThread);
+ }
private:
RenderThread* mRenderThread;
@@ -145,29 +137,24 @@ RenderThread::RenderThread()
}
RenderThread::~RenderThread() {
+ // Note that if this fatal assertion is removed then member variables must
+ // be properly destroyed.
LOG_ALWAYS_FATAL("Can't destroy the render thread");
}
-void RenderThread::initializeDisplayEventReceiver() {
- LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second DisplayEventReceiver?");
+void RenderThread::initializeChoreographer() {
+ LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second Choreographer?");
if (!Properties::isolatedProcess) {
- auto receiver = std::make_unique<DisplayEventReceiver>(
- ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::eConfigChangedDispatch);
- status_t status = receiver->initCheck();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "Initialization of DisplayEventReceiver "
- "failed with status: %d",
- status);
+ mChoreographer = AChoreographer_create();
+ LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
+ AChoreographer_registerRefreshRateCallback(mChoreographer,
+ RenderThread::refreshRateCallback, this);
// Register the FD
- mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
- RenderThread::displayEventReceiverCallback, this);
- mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
- DeviceInfo::get()->onDisplayConfigChanged();
- setupFrameInterval();
- });
+ mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
+ RenderThread::choreographerCallback, this);
+ mVsyncSource = new ChoreographerSource(this);
} else {
mVsyncSource = new DummyVsyncSource(this);
}
@@ -175,7 +162,7 @@ void RenderThread::initializeDisplayEventReceiver() {
void RenderThread::initThreadLocals() {
setupFrameInterval();
- initializeDisplayEventReceiver();
+ initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager();
@@ -183,7 +170,7 @@ void RenderThread::initThreadLocals() {
}
void RenderThread::setupFrameInterval() {
- nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / DeviceInfo::getRefreshRate());
+ nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
mTimeLord.setFrameInterval(frameIntervalNanos);
mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
}
@@ -288,7 +275,7 @@ void RenderThread::setGrContext(sk_sp<GrContext> context) {
}
}
-int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
+int RenderThread::choreographerCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x",
@@ -302,24 +289,10 @@ int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
events);
return 1; // keep the callback
}
+ RenderThread* rt = reinterpret_cast<RenderThread*>(data);
+ AChoreographer_handlePendingEvents(rt->mChoreographer, data);
- reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
-
- return 1; // keep the callback
-}
-
-void RenderThread::drainDisplayEventQueue() {
- ATRACE_CALL();
- nsecs_t vsyncEvent = mVsyncSource->latestVsyncEvent();
- if (vsyncEvent > 0) {
- mVsyncRequested = false;
- if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
- ATRACE_NAME("queue mFrameCallbackTask");
- mFrameCallbackTaskPending = true;
- nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay);
- queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
- }
- }
+ return 1;
}
void RenderThread::dispatchFrameCallbacks() {
@@ -360,7 +333,7 @@ bool RenderThread::threadLoop() {
processQueue();
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
- drainDisplayEventQueue();
+ mVsyncSource->drainPendingEvents();
mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index da79e97a6ceb..8be46a6d16e1 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,6 +19,7 @@
#include <GrContext.h>
#include <SkBitmap.h>
+#include <apex/choreographer.h>
#include <cutils/compiler.h>
#include <thread/ThreadBase.h>
#include <utils/Looper.h>
@@ -73,10 +74,11 @@ protected:
struct VsyncSource {
virtual void requestNextVsync() = 0;
- virtual nsecs_t latestVsyncEvent() = 0;
+ virtual void drainPendingEvents() = 0;
virtual ~VsyncSource() {}
};
+class ChoreographerSource;
class DummyVsyncSource;
typedef void (*JVMAttachHook)(const char* name);
@@ -136,6 +138,7 @@ private:
friend class DispatchFrameCallbacks;
friend class RenderProxy;
friend class DummyVsyncSource;
+ friend class ChoreographerSource;
friend class android::uirenderer::AutoBackendTextureRelease;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
@@ -149,13 +152,21 @@ private:
static RenderThread& getInstance();
void initThreadLocals();
- void initializeDisplayEventReceiver();
+ void initializeChoreographer();
void setupFrameInterval();
- static int displayEventReceiverCallback(int fd, int events, void* data);
+ // Callbacks for choreographer events:
+ // choreographerCallback will call AChoreograper_handleEvent to call the
+ // corresponding callbacks for each display event type
+ static int choreographerCallback(int fd, int events, void* data);
+ // Callback that will be run on vsync ticks.
+ static void frameCallback(int64_t frameTimeNanos, void* data);
+ // Callback that will be run whenver there is a refresh rate change.
+ static void refreshRateCallback(int64_t vsyncPeriod, void* data);
void drainDisplayEventQueue();
void dispatchFrameCallbacks();
void requestVsync();
+ AChoreographer* mChoreographer;
VsyncSource* mVsyncSource;
bool mVsyncRequested;
std::set<IFrameCallback*> mFrameCallbacks;
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 02a381669893..51fa4eeaf4d8 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -25,7 +25,7 @@ import android.media.IMediaRoute2ProviderClient;
oneway interface IMediaRoute2Provider {
void setClient(IMediaRoute2ProviderClient client);
void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId);
+ String routeType, long requestId);
void releaseSession(int sessionId);
void selectRoute(int sessionId, String routeId);
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index b7cb7059ce3d..e8af21e59cc1 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -24,7 +24,7 @@ import android.media.MediaRoute2Info;
*/
oneway interface IMediaRouter2Manager {
void notifyRouteSelected(String packageName, in MediaRoute2Info route);
- void notifyControlCategoriesChanged(String packageName, in List<String> categories);
+ void notifyRouteTypesChanged(String packageName, in List<String> routeTypes);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index e5b62ff10aa6..b573f64da51d 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -22,6 +22,7 @@ import android.media.IMediaRouter2Manager;
import android.media.IMediaRouterClient;
import android.media.MediaRoute2Info;
import android.media.MediaRouterClientState;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
/**
@@ -51,8 +52,8 @@ interface IMediaRouterService {
void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction);
void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route,
- String controlCategory, int requestId);
- void setControlCategories(IMediaRouter2Client client, in List<String> categories);
+ String routeType, int requestId);
+ void setDiscoveryRequest2(IMediaRouter2Client client, in RouteDiscoveryRequest request);
void selectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
void deselectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
void transferToRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 7fca03cdfd57..4cd581b6628c 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -354,8 +355,8 @@ public class MediaMetadataRetriever implements AutoCloseable {
* is less than or equal to 0.
* @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
*/
- public @Nullable Bitmap getScaledFrameAtTime(
- long timeUs, @Option int option, int dstWidth, int dstHeight) {
+ public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
}
@@ -400,7 +401,8 @@ public class MediaMetadataRetriever implements AutoCloseable {
* @see {@link #getScaledFrameAtTime(long, int, int, int)}
*/
public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
- int dstWidth, int dstHeight, @NonNull BitmapParams params) {
+ @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight,
+ @NonNull BitmapParams params) {
validate(option, dstWidth, dstHeight);
return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 506d6165bbfa..13640a438e7b 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -83,12 +83,14 @@ public final class MediaRoute2Info implements Parcelable {
* controlled from this object. An example of fixed playback volume is a remote player,
* playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
* than attenuate at the source.
+ *
* @see #getVolumeHandling()
*/
public static final int PLAYBACK_VOLUME_FIXED = 0;
/**
* Playback information indicating the playback volume is variable and can be controlled
* from this object.
+ *
* @see #getVolumeHandling()
*/
public static final int PLAYBACK_VOLUME_VARIABLE = 1;
@@ -148,7 +150,7 @@ public final class MediaRoute2Info implements Parcelable {
@Nullable
final String mClientPackageName;
@NonNull
- final List<String> mSupportedCategories;
+ final List<String> mRouteTypes;
final int mVolume;
final int mVolumeMax;
final int mVolumeHandling;
@@ -156,8 +158,6 @@ public final class MediaRoute2Info implements Parcelable {
@Nullable
final Bundle mExtras;
- private final String mUniqueId;
-
MediaRoute2Info(@NonNull Builder builder) {
mId = builder.mId;
mProviderId = builder.mProviderId;
@@ -166,13 +166,12 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = builder.mConnectionState;
mIconUri = builder.mIconUri;
mClientPackageName = builder.mClientPackageName;
- mSupportedCategories = builder.mSupportedCategories;
+ mRouteTypes = builder.mRouteTypes;
mVolume = builder.mVolume;
mVolumeMax = builder.mVolumeMax;
mVolumeHandling = builder.mVolumeHandling;
mDeviceType = builder.mDeviceType;
mExtras = builder.mExtras;
- mUniqueId = createUniqueId();
}
MediaRoute2Info(@NonNull Parcel in) {
@@ -183,24 +182,18 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = in.readInt();
mIconUri = in.readParcelable(null);
mClientPackageName = in.readString();
- mSupportedCategories = in.createStringArrayList();
+ mRouteTypes = in.createStringArrayList();
mVolume = in.readInt();
mVolumeMax = in.readInt();
mVolumeHandling = in.readInt();
mDeviceType = in.readInt();
mExtras = in.readBundle();
- mUniqueId = createUniqueId();
- }
-
- private String createUniqueId() {
- String uniqueId = null;
- if (mProviderId != null) {
- uniqueId = toUniqueId(mProviderId, mId);
- }
- return uniqueId;
}
- static String toUniqueId(String providerId, String routeId) {
+ /**
+ * @hide
+ */
+ public static String toUniqueId(String providerId, String routeId) {
return providerId + ":" + routeId;
}
@@ -235,7 +228,7 @@ public final class MediaRoute2Info implements Parcelable {
&& (mConnectionState == other.mConnectionState)
&& Objects.equals(mIconUri, other.mIconUri)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
- && Objects.equals(mSupportedCategories, other.mSupportedCategories)
+ && Objects.equals(mRouteTypes, other.mRouteTypes)
&& (mVolume == other.mVolume)
&& (mVolumeMax == other.mVolumeMax)
&& (mVolumeHandling == other.mVolumeHandling)
@@ -247,29 +240,34 @@ public final class MediaRoute2Info implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mId, mName, mDescription, mConnectionState, mIconUri,
- mSupportedCategories, mVolume, mVolumeMax, mVolumeHandling, mDeviceType);
+ mRouteTypes, mVolume, mVolumeMax, mVolumeHandling, mDeviceType);
}
/**
- * Gets the id of the route.
- * Use {@link #getUniqueId()} if you need a unique identifier.
+ * Gets the id of the route. The routes which are given by {@link MediaRouter2} will have
+ * unique IDs.
+ * <p>
+ * In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
+ * can be different from what was set in {@link MediaRoute2ProviderService}.
*
- * @see #getUniqueId()
+ * @see Builder#setId(String)
*/
@NonNull
public String getId() {
- return mId;
+ if (mProviderId != null) {
+ return toUniqueId(mProviderId, mId);
+ } else {
+ return mId;
+ }
}
/**
- * Gets the unique id of the route. A route obtained from
- * {@link com.android.server.media.MediaRouterService} always has a unique id.
- *
- * @return unique id of the route or null if it has no unique id.
+ * Gets the original id set by {@link Builder#setId(String)}.
+ * @hide
*/
- @Nullable
- public String getUniqueId() {
- return mUniqueId;
+ @NonNull
+ public String getOriginalId() {
+ return mId;
}
/**
@@ -331,8 +329,8 @@ public final class MediaRoute2Info implements Parcelable {
* Gets the supported categories of the route.
*/
@NonNull
- public List<String> getSupportedCategories() {
- return mSupportedCategories;
+ public List<String> getRouteTypes() {
+ return mRouteTypes;
}
//TODO: once device types are confirmed, reflect those into the comment.
@@ -376,32 +374,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Returns if the route supports the specified control category
+ * Returns if the route contains at least one of the specified route types.
*
- * @param controlCategory control category to consider
- * @return true if the route supports at the category
+ * @param routeTypes the list of route types to consider
+ * @return true if the route contains at least one type in the list
*/
- public boolean supportsControlCategory(@NonNull String controlCategory) {
- Objects.requireNonNull(controlCategory, "control category must not be null");
- for (String supportedCategory : getSupportedCategories()) {
- if (TextUtils.equals(controlCategory, supportedCategory)) {
- return true;
- }
- }
- return false;
- }
-
- //TODO: Move this if we re-define control category / selector things.
- /**
- * Returns if the route supports at least one of the specified control categories
- *
- * @param controlCategories the list of control categories to consider
- * @return true if the route supports at least one category
- */
- public boolean supportsControlCategories(@NonNull Collection<String> controlCategories) {
- Objects.requireNonNull(controlCategories, "control categories must not be null");
- for (String controlCategory : controlCategories) {
- if (supportsControlCategory(controlCategory)) {
+ public boolean containsRouteTypes(@NonNull Collection<String> routeTypes) {
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null");
+ for (String routeType : routeTypes) {
+ if (getRouteTypes().contains(routeType)) {
return true;
}
}
@@ -422,7 +403,7 @@ public final class MediaRoute2Info implements Parcelable {
dest.writeInt(mConnectionState);
dest.writeParcelable(mIconUri, flags);
dest.writeString(mClientPackageName);
- dest.writeStringList(mSupportedCategories);
+ dest.writeStringList(mRouteTypes);
dest.writeInt(mVolume);
dest.writeInt(mVolumeMax);
dest.writeInt(mVolumeHandling);
@@ -460,7 +441,7 @@ public final class MediaRoute2Info implements Parcelable {
int mConnectionState;
Uri mIconUri;
String mClientPackageName;
- List<String> mSupportedCategories;
+ List<String> mRouteTypes;
int mVolume;
int mVolumeMax;
int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
@@ -471,7 +452,7 @@ public final class MediaRoute2Info implements Parcelable {
public Builder(@NonNull String id, @NonNull CharSequence name) {
setId(id);
setName(name);
- mSupportedCategories = new ArrayList<>();
+ mRouteTypes = new ArrayList<>();
}
public Builder(@NonNull MediaRoute2Info routeInfo) {
@@ -488,7 +469,7 @@ public final class MediaRoute2Info implements Parcelable {
mConnectionState = routeInfo.mConnectionState;
mIconUri = routeInfo.mIconUri;
setClientPackageName(routeInfo.mClientPackageName);
- setSupportedCategories(routeInfo.mSupportedCategories);
+ setRouteTypes(routeInfo.mRouteTypes);
setVolume(routeInfo.mVolume);
setVolumeMax(routeInfo.mVolumeMax);
setVolumeHandling(routeInfo.mVolumeHandling);
@@ -499,7 +480,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Sets the unique id of the route.
+ * Sets the unique id of the route. The value given here must be unique for each of your
+ * route.
+ * <p>
+ * In order to ensure uniqueness in {@link MediaRouter2} side, the value of
+ * {@link MediaRoute2Info#getId()} can be different from what was set in
+ * {@link MediaRoute2ProviderService}.
+ * </p>
+ *
+ * @see MediaRoute2Info#getId()
*/
@NonNull
public Builder setId(@NonNull String id) {
@@ -585,35 +574,35 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Sets the supported categories of the route.
+ * Sets the types of the route.
*/
@NonNull
- public Builder setSupportedCategories(@NonNull Collection<String> categories) {
- mSupportedCategories = new ArrayList<>();
- return addSupportedCategories(categories);
+ public Builder setRouteTypes(@NonNull Collection<String> routeTypes) {
+ mRouteTypes = new ArrayList<>();
+ return addRouteTypes(routeTypes);
}
/**
- * Adds supported categories for the route.
+ * Adds types for the route.
*/
@NonNull
- public Builder addSupportedCategories(@NonNull Collection<String> categories) {
- Objects.requireNonNull(categories, "categories must not be null");
- for (String category: categories) {
- addSupportedCategory(category);
+ public Builder addRouteTypes(@NonNull Collection<String> routeTypes) {
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null");
+ for (String routeType: routeTypes) {
+ addRouteType(routeType);
}
return this;
}
/**
- * Add a supported category for the route.
+ * Add a type for the route.
*/
@NonNull
- public Builder addSupportedCategory(@NonNull String category) {
- if (TextUtils.isEmpty(category)) {
- throw new IllegalArgumentException("category must not be null or empty");
+ public Builder addRouteType(@NonNull String routeType) {
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be null or empty");
}
- mSupportedCategories.add(category);
+ mRouteTypes.add(routeType);
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 7078d4a0b568..e2f246cae8c2 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -25,6 +25,7 @@ import android.util.ArrayMap;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Map;
import java.util.Objects;
/**
@@ -161,14 +162,17 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
return this;
}
mUniqueId = uniqueId;
- final int count = mRoutes.size();
- for (int i = 0; i < count; i++) {
- MediaRoute2Info route = mRoutes.valueAt(i);
- mRoutes.setValueAt(i, new MediaRoute2Info.Builder(route)
+
+ final ArrayMap<String, MediaRoute2Info> newRoutes = new ArrayMap<>();
+ for (Map.Entry<String, MediaRoute2Info> entry : mRoutes.entrySet()) {
+ MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue())
.setProviderId(mUniqueId)
- .build());
+ .build();
+ newRoutes.put(routeWithProviderId.getId(), routeWithProviderId);
}
+ mRoutes.clear();
+ mRoutes.putAll(newRoutes);
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 99bd1dcde3bb..91cc44807a73 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -246,11 +246,11 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route initially being connected
- * @param controlCategory the control category of the new session
+ * @param routeType the route type of the new session
* @param requestId the id of this session creation request
*/
public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
- @NonNull String controlCategory, long requestId);
+ @NonNull String routeType, long requestId);
/**
* Called when a session is about to be destroyed.
@@ -301,6 +301,25 @@ public abstract class MediaRoute2ProviderService extends Service {
public abstract void onTransferToRoute(int sessionId, @NonNull String routeId);
/**
+ * Called when the {@link RouteDiscoveryRequest discovery request} has changed.
+ * <p>
+ * Whenever an application registers a {@link MediaRouter2.RouteCallback callback},
+ * it also provides a discovery request to specify types of routes that it is interested in.
+ * The media router combines all of these discovery request into a single discovery request
+ * and notifies each provider.
+ * </p><p>
+ * The provider should examine {@link RouteDiscoveryRequest#getRouteTypes() route types}
+ * in the discovery request to determine what kind of routes it should try to discover
+ * and whether it should perform active or passive scans. In many cases, the provider may be
+ * able to save power by not performing any scans when the request doesn't have any matching
+ * route types.
+ * </p>
+ *
+ * @param request the new discovery request
+ */
+ public void onDiscoveryRequestChanged(@NonNull RouteDiscoveryRequest request) {}
+
+ /**
* Updates provider info and publishes routes and session info.
*/
public final void updateProviderInfo(@NonNull MediaRoute2ProviderInfo providerInfo) {
@@ -357,12 +376,12 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId) {
+ String routeType, long requestId) {
if (!checkCallerisSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
- MediaRoute2ProviderService.this, packageName, routeId, controlCategory,
+ MediaRoute2ProviderService.this, packageName, routeId, routeType,
requestId));
}
@Override
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index f5cfde4b968b..dea8b045e72a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -39,7 +39,6 @@ import com.android.internal.annotations.GuardedBy;
import java.lang.annotation.Retention;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -48,6 +47,7 @@ import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
/**
* A new Media Router
@@ -118,7 +118,7 @@ public class MediaRouter2 {
final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
@GuardedBy("sLock")
- private List<String> mControlCategories = Collections.emptyList();
+ private RouteDiscoveryRequest mDiscoveryRequest = RouteDiscoveryRequest.EMPTY;
// TODO: Make MediaRouter2 is always connected to the MediaRouterService.
@GuardedBy("sLock")
@@ -152,7 +152,6 @@ public class MediaRouter2 {
mMediaRouterService = IMediaRouterService.Stub.asInterface(
ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
mPackageName = mContext.getPackageName();
- //TODO: read control categories from the manifest
mHandler = new Handler(Looper.getMainLooper());
List<MediaRoute2Info> currentSystemRoutes = null;
@@ -177,9 +176,9 @@ public class MediaRouter2 {
* @hide
*/
public static boolean checkRouteListContainsRouteId(@NonNull List<MediaRoute2Info> routeList,
- @NonNull String uniqueRouteId) {
+ @NonNull String routeId) {
for (MediaRoute2Info info : routeList) {
- if (TextUtils.equals(uniqueRouteId, info.getUniqueId())) {
+ if (TextUtils.equals(routeId, info.getId())) {
return true;
}
}
@@ -188,24 +187,18 @@ public class MediaRouter2 {
/**
* Registers a callback to discover routes and to receive events when they change.
- */
- public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull RouteCallback routeCallback) {
- registerRouteCallback(executor, routeCallback, 0);
- }
-
- /**
- * Registers a callback to discover routes and to receive events when they change.
* <p>
* If you register the same callback twice or more, it will be ignored.
* </p>
*/
public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull RouteCallback routeCallback, int flags) {
+ @NonNull RouteCallback routeCallback,
+ @NonNull RouteDiscoveryRequest request) {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(routeCallback, "callback must not be null");
+ Objects.requireNonNull(request, "request must not be null");
- RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, flags);
+ RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, request);
if (!mRouteCallbackRecords.addIfAbsent(record)) {
Log.w(TAG, "Ignoring the same callback");
return;
@@ -216,7 +209,8 @@ public class MediaRouter2 {
Client2 client = new Client2();
try {
mMediaRouterService.registerClient2(client, mPackageName);
- mMediaRouterService.setControlCategories(client, mControlCategories);
+ updateDiscoveryRequestLocked();
+ mMediaRouterService.setDiscoveryRequest2(client, mDiscoveryRequest);
mClient = client;
} catch (RemoteException ex) {
Log.e(TAG, "Unable to register media router.", ex);
@@ -238,7 +232,7 @@ public class MediaRouter2 {
Objects.requireNonNull(routeCallback, "callback must not be null");
if (!mRouteCallbackRecords.remove(
- new RouteCallbackRecord(null, routeCallback, 0))) {
+ new RouteCallbackRecord(null, routeCallback, null))) {
Log.w(TAG, "Ignoring unknown callback");
return;
}
@@ -256,30 +250,10 @@ public class MediaRouter2 {
}
}
- //TODO(b/139033746): Rename "Control Category" when it's finalized.
- /**
- * Sets the control categories of the application.
- * Routes that support at least one of the given control categories are handled
- * by the media router.
- */
- public void setControlCategories(@NonNull Collection<String> controlCategories) {
- Objects.requireNonNull(controlCategories, "control categories must not be null");
-
- List<String> newControlCategories = new ArrayList<>(controlCategories);
-
- synchronized (sRouterLock) {
- mShouldUpdateRoutes = true;
-
- // invoke callbacks due to control categories change
- handleControlCategoriesChangedLocked(newControlCategories);
- if (mClient != null) {
- try {
- mMediaRouterService.setControlCategories(mClient, mControlCategories);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to set control categories.", ex);
- }
- }
- }
+ private void updateDiscoveryRequestLocked() {
+ mDiscoveryRequest = new RouteDiscoveryRequest.Builder(
+ mRouteCallbackRecords.stream().map(record -> record.mRequest).collect(
+ Collectors.toList())).build();
}
/**
@@ -287,8 +261,8 @@ public class MediaRouter2 {
* known to the media router.
* Please note that the list can be changed before callbacks are invoked.
*
- * @return the list of routes that support at least one of the control categories set by
- * the application
+ * @return the list of routes that contains at least one of the route types in discovery
+ * requests registered by the application
*/
@NonNull
public List<MediaRoute2Info> getRoutes() {
@@ -298,7 +272,7 @@ public class MediaRouter2 {
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.supportsControlCategories(mControlCategories)) {
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
filteredRoutes.add(route);
}
}
@@ -350,26 +324,26 @@ public class MediaRouter2 {
* Requests the media route provider service to create a session with the given route.
*
* @param route the route you want to create a session with.
- * @param controlCategory the control category of the session. Should not be empty
+ * @param routeType the route type of the session. Should not be empty
*
* @see SessionCallback#onSessionCreated
* @see SessionCallback#onSessionCreationFailed
*/
@NonNull
public void requestCreateSession(@NonNull MediaRoute2Info route,
- @NonNull String controlCategory) {
+ @NonNull String routeType) {
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(controlCategory)) {
- throw new IllegalArgumentException("controlCategory must not be empty");
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be empty");
}
// TODO: Check the given route exists
- // TODO: Check the route supports the given controlCategory
+ // TODO: Check the route supports the given routeType
final int requestId;
requestId = mSessionCreationRequestCnt.getAndIncrement();
SessionCreationRequest request = new SessionCreationRequest(
- requestId, route, controlCategory);
+ requestId, route, routeType);
mSessionCreationRequests.add(request);
Client2 client;
@@ -379,7 +353,7 @@ public class MediaRouter2 {
if (client != null) {
try {
mMediaRouterService.requestCreateSession(
- client, route, controlCategory, requestId);
+ client, route, routeType, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to request to create session.", ex);
mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
@@ -461,36 +435,6 @@ public class MediaRouter2 {
}
}
- private void handleControlCategoriesChangedLocked(List<String> newControlCategories) {
- List<MediaRoute2Info> addedRoutes = new ArrayList<>();
- List<MediaRoute2Info> removedRoutes = new ArrayList<>();
-
- List<String> prevControlCategories = mControlCategories;
- mControlCategories = newControlCategories;
-
- for (MediaRoute2Info route : mRoutes.values()) {
- boolean preSupported = route.supportsControlCategories(prevControlCategories);
- boolean postSupported = route.supportsControlCategories(newControlCategories);
- if (preSupported == postSupported) {
- continue;
- }
- if (preSupported) {
- removedRoutes.add(route);
- } else {
- addedRoutes.add(route);
- }
- }
-
- if (removedRoutes.size() > 0) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesRemoved,
- MediaRouter2.this, removedRoutes));
- }
- if (addedRoutes.size() > 0) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesAdded,
- MediaRouter2.this, addedRoutes));
- }
- }
-
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
// TODO: When onRoutesAdded is first called,
// 1) clear mRoutes before adding the routes
@@ -499,8 +443,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.put(route.getId(), route);
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
addedRoutes.add(route);
}
}
@@ -515,8 +459,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.remove(route.getUniqueId());
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.remove(route.getId());
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
removedRoutes.add(route);
}
}
@@ -531,8 +475,8 @@ public class MediaRouter2 {
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
- if (route.supportsControlCategories(mControlCategories)) {
+ mRoutes.put(route.getId(), route);
+ if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) {
changedRoutes.add(route);
}
}
@@ -562,27 +506,27 @@ public class MediaRouter2 {
mSessionCreationRequests.remove(matchingRequest);
MediaRoute2Info requestedRoute = matchingRequest.mRoute;
- String requestedControlCategory = matchingRequest.mControlCategory;
+ String requestedRouteType = matchingRequest.mRouteType;
if (sessionInfo == null) {
// TODO: We may need to distinguish between failure and rejection.
// One way can be introducing 'reason'.
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
- } else if (!TextUtils.equals(requestedControlCategory,
- sessionInfo.getControlCategory())) {
- Log.w(TAG, "The session has different control category from what we requested. "
- + "(requested=" + requestedControlCategory
- + ", actual=" + sessionInfo.getControlCategory()
+ } else if (!TextUtils.equals(requestedRouteType,
+ sessionInfo.getRouteType())) {
+ Log.w(TAG, "The session has different route type from what we requested. "
+ + "(requested=" + requestedRouteType
+ + ", actual=" + sessionInfo.getRouteType()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
} else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
Log.w(TAG, "The session does not contain the requested route. "
+ "(requestedRouteId=" + requestedRoute.getId()
+ ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
} else if (!TextUtils.equals(requestedRoute.getProviderId(),
sessionInfo.getProviderId())) {
@@ -590,7 +534,7 @@ public class MediaRouter2 {
+ "(requested route's providerId=" + requestedRoute.getProviderId()
+ ", actual providerId=" + sessionInfo.getProviderId()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ notifySessionCreationFailed(requestedRoute, requestedRouteType);
return;
}
}
@@ -666,24 +610,41 @@ public class MediaRouter2 {
notifyControllerReleased(matchingController);
}
+ private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
+ RouteDiscoveryRequest discoveryRequest) {
+ return routes.stream()
+ .filter(
+ route -> route.containsRouteTypes(discoveryRequest.getRouteTypes()))
+ .collect(Collectors.toList());
+ }
+
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesAdded(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesAdded(filteredRoutes));
+ }
}
}
private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesRemoved(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesRemoved(filteredRoutes));
+ }
}
}
private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesChanged(routes));
+ List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest);
+ if (!filteredRoutes.isEmpty()) {
+ record.mExecutor.execute(
+ () -> record.mRouteCallback.onRoutesChanged(filteredRoutes));
+ }
}
}
@@ -694,10 +655,10 @@ public class MediaRouter2 {
}
}
- private void notifySessionCreationFailed(MediaRoute2Info route, String controlCategory) {
+ private void notifySessionCreationFailed(MediaRoute2Info route, String routeType) {
for (SessionCallbackRecord record: mSessionCallbackRecords) {
record.mExecutor.execute(
- () -> record.mSessionCallback.onSessionCreationFailed(route, controlCategory));
+ () -> record.mSessionCallback.onSessionCreationFailed(route, routeType));
}
}
@@ -764,10 +725,10 @@ public class MediaRouter2 {
* Called when the session creation request failed.
*
* @param requestedRoute the route info which was used for the request
- * @param requestedControlCategory the control category which was used for the request
+ * @param requestedRouteType the route type which was used for the request
*/
public void onSessionCreationFailed(@NonNull MediaRoute2Info requestedRoute,
- @NonNull String requestedControlCategory) {}
+ @NonNull String requestedRouteType) {}
/**
* Called when the session info has changed.
@@ -840,12 +801,12 @@ public class MediaRouter2 {
}
/**
- * @return the category of routes that the session includes.
+ * @return the type of routes that the session includes.
*/
@NonNull
- public String getControlCategory() {
+ public String getRouteType() {
synchronized (mControllerLock) {
- return mSessionInfo.getControlCategory();
+ return mSessionInfo.getRouteType();
}
}
@@ -935,13 +896,13 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a route that is already selected. route=" + route);
return;
}
List<MediaRoute2Info> selectableRoutes = getSelectableRoutes();
- if (!checkRouteListContainsRouteId(selectableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(selectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring selecting a non-selectable route=" + route);
return;
}
@@ -982,13 +943,13 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (!checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a route that is not selected. route=" + route);
return;
}
List<MediaRoute2Info> deselectableRoutes = getDeselectableRoutes();
- if (!checkRouteListContainsRouteId(deselectableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(deselectableRoutes, route.getId())) {
Log.w(TAG, "Ignoring deselecting a non-deselectable route=" + route);
return;
}
@@ -1029,14 +990,14 @@ public class MediaRouter2 {
}
List<MediaRoute2Info> selectedRoutes = getSelectedRoutes();
- if (checkRouteListContainsRouteId(selectedRoutes, route.getUniqueId())) {
+ if (checkRouteListContainsRouteId(selectedRoutes, route.getId())) {
Log.w(TAG, "Ignoring transferring to a route that is already added. route="
+ route);
return;
}
List<MediaRoute2Info> transferrableRoutes = getTransferrableRoutes();
- if (!checkRouteListContainsRouteId(transferrableRoutes, route.getUniqueId())) {
+ if (!checkRouteListContainsRouteId(transferrableRoutes, route.getId())) {
Log.w(TAG, "Ignoring transferring to a non-transferrable route=" + route);
return;
}
@@ -1084,8 +1045,12 @@ public class MediaRouter2 {
}
}
+ /**
+ * TODO: Change this to package private. (Hidden for debugging purposes)
+ * @hide
+ */
@NonNull
- RouteSessionInfo getRouteSessionInfo() {
+ public RouteSessionInfo getRouteSessionInfo() {
synchronized (mControllerLock) {
return mSessionInfo;
}
@@ -1100,11 +1065,11 @@ public class MediaRouter2 {
// TODO: This method uses two locks (mLock outside, sLock inside).
// Check if there is any possiblity of deadlock.
private List<MediaRoute2Info> getRoutesWithIdsLocked(List<String> routeIds) {
+
List<MediaRoute2Info> routes = new ArrayList<>();
synchronized (sRouterLock) {
for (String routeId : routeIds) {
- MediaRoute2Info route = mRoutes.get(
- MediaRoute2Info.toUniqueId(mSessionInfo.mProviderId, routeId));
+ MediaRoute2Info route = mRoutes.get(routeId);
if (route != null) {
routes.add(route);
}
@@ -1117,13 +1082,13 @@ public class MediaRouter2 {
final class RouteCallbackRecord {
public final Executor mExecutor;
public final RouteCallback mRouteCallback;
- public final int mFlags;
+ public final RouteDiscoveryRequest mRequest;
RouteCallbackRecord(@Nullable Executor executor, @NonNull RouteCallback routeCallback,
- int flags) {
+ @Nullable RouteDiscoveryRequest request) {
mRouteCallback = routeCallback;
mExecutor = executor;
- mFlags = flags;
+ mRequest = request;
}
@Override
@@ -1172,13 +1137,13 @@ public class MediaRouter2 {
final class SessionCreationRequest {
public final MediaRoute2Info mRoute;
- public final String mControlCategory;
+ public final String mRouteType;
public final int mRequestId;
SessionCreationRequest(int requestId, @NonNull MediaRoute2Info route,
- @NonNull String controlCategory) {
+ @NonNull String routeType) {
mRoute = route;
- mControlCategory = controlCategory;
+ mRouteType = routeType;
mRequestId = requestId;
}
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 2e68e42e714f..1e6ec51442d6 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -65,7 +65,7 @@ public class MediaRouter2Manager {
@GuardedBy("mRoutesLock")
private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
@NonNull
- final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
+ final ConcurrentMap<String, List<String>> mRouteTypeMap = new ConcurrentHashMap<>();
private AtomicInteger mNextRequestId = new AtomicInteger(1);
@@ -144,7 +144,7 @@ public class MediaRouter2Manager {
}
//TODO: clear mRoutes?
mClient = null;
- mControlCategoryMap.clear();
+ mRouteTypeMap.clear();
}
}
}
@@ -160,14 +160,14 @@ public class MediaRouter2Manager {
public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
- List<String> controlCategories = mControlCategoryMap.get(packageName);
- if (controlCategories == null) {
+ List<String> routeTypes = mRouteTypeMap.get(packageName);
+ if (routeTypes == null) {
return Collections.emptyList();
}
List<MediaRoute2Info> routes = new ArrayList<>();
synchronized (mRoutesLock) {
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.supportsControlCategories(controlCategories)) {
+ if (route.containsRouteTypes(routeTypes)) {
routes.add(route);
}
}
@@ -295,7 +295,7 @@ public class MediaRouter2Manager {
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
+ mRoutes.put(route.getId(), route);
}
}
if (routes.size() > 0) {
@@ -306,7 +306,7 @@ public class MediaRouter2Manager {
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.remove(route.getUniqueId());
+ mRoutes.remove(route.getId());
}
}
if (routes.size() > 0) {
@@ -317,7 +317,7 @@ public class MediaRouter2Manager {
void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
synchronized (mRoutesLock) {
for (MediaRoute2Info route : routes) {
- mRoutes.put(route.getUniqueId(), route);
+ mRoutes.put(route.getId(), route);
}
}
if (routes.size() > 0) {
@@ -352,15 +352,15 @@ public class MediaRouter2Manager {
}
}
- void updateControlCategories(String packageName, List<String> categories) {
- List<String> prevCategories = mControlCategoryMap.put(packageName, categories);
- if ((prevCategories == null && categories.size() == 0)
- || Objects.equals(categories, prevCategories)) {
+ void updateRouteTypes(String packageName, List<String> routeTypes) {
+ List<String> prevTypes = mRouteTypeMap.put(packageName, routeTypes);
+ if ((prevTypes == null && routeTypes.size() == 0)
+ || Objects.equals(routeTypes, prevTypes)) {
return;
}
for (CallbackRecord record : mCallbackRecords) {
record.mExecutor.execute(
- () -> record.mCallback.onControlCategoriesChanged(packageName, categories));
+ () -> record.mCallback.onControlCategoriesChanged(packageName, routeTypes));
}
}
@@ -398,13 +398,13 @@ public class MediaRouter2Manager {
/**
- * Called when the control categories of an app is changed.
+ * Called when the route types of an app is changed.
*
* @param packageName the package name of the application
- * @param controlCategories the list of control categories set by an application.
+ * @param routeTypes the list of route types set by an application.
*/
public void onControlCategoriesChanged(@NonNull String packageName,
- @NonNull List<String> controlCategories) {}
+ @NonNull List<String> routeTypes) {}
}
final class CallbackRecord {
@@ -440,10 +440,9 @@ public class MediaRouter2Manager {
MediaRouter2Manager.this, packageName, route));
}
- @Override
- public void notifyControlCategoriesChanged(String packageName, List<String> categories) {
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateControlCategories,
- MediaRouter2Manager.this, packageName, categories));
+ public void notifyRouteTypesChanged(String packageName, List<String> routeTypes) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateRouteTypes,
+ MediaRouter2Manager.this, packageName, routeTypes));
}
@Override
diff --git a/media/java/android/media/RouteDiscoveryRequest.aidl b/media/java/android/media/RouteDiscoveryRequest.aidl
new file mode 100644
index 000000000000..744f6569325d
--- /dev/null
+++ b/media/java/android/media/RouteDiscoveryRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable RouteDiscoveryRequest;
diff --git a/media/java/android/media/RouteDiscoveryRequest.java b/media/java/android/media/RouteDiscoveryRequest.java
new file mode 100644
index 000000000000..88b31fb30ffc
--- /dev/null
+++ b/media/java/android/media/RouteDiscoveryRequest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+
+/**
+ * @hide
+ */
+public final class RouteDiscoveryRequest implements Parcelable {
+ @NonNull
+ public static final Creator<RouteDiscoveryRequest> CREATOR =
+ new Creator<RouteDiscoveryRequest>() {
+ @Override
+ public RouteDiscoveryRequest createFromParcel(Parcel in) {
+ return new RouteDiscoveryRequest(in);
+ }
+
+ @Override
+ public RouteDiscoveryRequest[] newArray(int size) {
+ return new RouteDiscoveryRequest[size];
+ }
+ };
+
+ @NonNull
+ private final List<String> mRouteTypes;
+ private final boolean mActiveScan;
+ @Nullable
+ private final Bundle mExtras;
+
+ /**
+ * @hide
+ */
+ public static final RouteDiscoveryRequest EMPTY =
+ new Builder(Collections.emptyList(), false).build();
+
+ RouteDiscoveryRequest(@NonNull Builder builder) {
+ mRouteTypes = builder.mRouteTypes;
+ mActiveScan = builder.mActiveScan;
+ mExtras = builder.mExtras;
+ }
+
+ RouteDiscoveryRequest(@NonNull Parcel in) {
+ mRouteTypes = in.createStringArrayList();
+ mActiveScan = in.readBoolean();
+ mExtras = in.readBundle();
+ }
+
+ @NonNull
+ public List<String> getRouteTypes() {
+ return mRouteTypes;
+ }
+
+ public boolean isActiveScan() {
+ return mActiveScan;
+ }
+
+ /**
+ * @hide
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStringList(mRouteTypes);
+ dest.writeBoolean(mActiveScan);
+ dest.writeBundle(mExtras);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder()
+ .append("RouteDiscoveryRequest{ ")
+ .append("routeTypes={")
+ .append(String.join(", ", mRouteTypes))
+ .append("}")
+ .append(", activeScan=")
+ .append(mActiveScan)
+ .append(" }");
+
+ return result.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RouteDiscoveryRequest)) {
+ return false;
+ }
+ RouteDiscoveryRequest other = (RouteDiscoveryRequest) o;
+ return Objects.equals(mRouteTypes, other.mRouteTypes)
+ && mActiveScan == other.mActiveScan;
+ }
+
+ /**
+ * Builder for {@link RouteDiscoveryRequest}.
+ */
+ public static final class Builder {
+ List<String> mRouteTypes;
+ boolean mActiveScan;
+ Bundle mExtras;
+
+ public Builder(@NonNull List<String> routeTypes, boolean activeScan) {
+ mRouteTypes = new ArrayList<>(
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null"));
+ mActiveScan = activeScan;
+ }
+
+ public Builder(@NonNull RouteDiscoveryRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ mRouteTypes = request.getRouteTypes();
+ mActiveScan = request.isActiveScan();
+ mExtras = request.getExtras();
+ }
+
+ /**
+ * A constructor to combine all of the requests into a single request.
+ * It ignores extras of requests.
+ */
+ Builder(@NonNull Collection<RouteDiscoveryRequest> requests) {
+ Set<String> routeTypeSet = new HashSet<>();
+ mActiveScan = false;
+ for (RouteDiscoveryRequest request : requests) {
+ routeTypeSet.addAll(request.mRouteTypes);
+ mActiveScan |= request.mActiveScan;
+ }
+ mRouteTypes = new ArrayList<>(routeTypeSet);
+ }
+
+ /**
+ * Sets route types to discover.
+ */
+ public Builder setRouteTypes(@NonNull List<String> routeTypes) {
+ mRouteTypes = new ArrayList<>(
+ Objects.requireNonNull(routeTypes, "routeTypes must not be null"));
+ return this;
+ }
+
+ /**
+ * Sets if active scanning should be performed.
+ */
+ public Builder setActiveScan(boolean activeScan) {
+ mActiveScan = activeScan;
+ return this;
+ }
+
+ /**
+ * Sets the extras of the route.
+ * @hide
+ */
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Builds the {@link RouteDiscoveryRequest}.
+ */
+ public RouteDiscoveryRequest build() {
+ return new RouteDiscoveryRequest(this);
+ }
+ }
+}
diff --git a/media/java/android/media/RouteSessionInfo.java b/media/java/android/media/RouteSessionInfo.java
index 2d7bc24ae7a2..cb1688600fac 100644
--- a/media/java/android/media/RouteSessionInfo.java
+++ b/media/java/android/media/RouteSessionInfo.java
@@ -48,7 +48,7 @@ public class RouteSessionInfo implements Parcelable {
final int mSessionId;
final String mPackageName;
- final String mControlCategory;
+ final String mRouteType;
@Nullable
final String mProviderId;
final List<String> mSelectedRoutes;
@@ -63,7 +63,7 @@ public class RouteSessionInfo implements Parcelable {
mSessionId = builder.mSessionId;
mPackageName = builder.mPackageName;
- mControlCategory = builder.mControlCategory;
+ mRouteType = builder.mRouteType;
mProviderId = builder.mProviderId;
mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes);
@@ -79,7 +79,7 @@ public class RouteSessionInfo implements Parcelable {
mSessionId = src.readInt();
mPackageName = ensureString(src.readString());
- mControlCategory = ensureString(src.readString());
+ mRouteType = ensureString(src.readString());
mProviderId = src.readString();
mSelectedRoutes = ensureList(src.createStringArrayList());
@@ -154,7 +154,7 @@ public class RouteSessionInfo implements Parcelable {
*/
public boolean isValid() {
return !TextUtils.isEmpty(mPackageName)
- && !TextUtils.isEmpty(mControlCategory)
+ && !TextUtils.isEmpty(mRouteType)
&& mSelectedRoutes.size() > 0;
}
@@ -175,12 +175,12 @@ public class RouteSessionInfo implements Parcelable {
}
/**
- * Gets the control category of the session.
- * Routes that don't support the category can't be added to the session.
+ * Gets the route type of the session.
+ * Routes that don't have the type can't be added to the session.
*/
@NonNull
- public String getControlCategory() {
- return mControlCategory;
+ public String getRouteType() {
+ return mRouteType;
}
/**
@@ -254,7 +254,7 @@ public class RouteSessionInfo implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mSessionId);
dest.writeString(mPackageName);
- dest.writeString(mControlCategory);
+ dest.writeString(mRouteType);
dest.writeString(mProviderId);
dest.writeStringList(mSelectedRoutes);
dest.writeStringList(mSelectableRoutes);
@@ -268,7 +268,7 @@ public class RouteSessionInfo implements Parcelable {
StringBuilder result = new StringBuilder()
.append("RouteSessionInfo{ ")
.append("sessionId=").append(mSessionId)
- .append(", controlCategory=").append(mControlCategory)
+ .append(", routeType=").append(mRouteType)
.append(", selectedRoutes={")
.append(String.join(",", mSelectedRoutes))
.append("}")
@@ -291,7 +291,7 @@ public class RouteSessionInfo implements Parcelable {
public static final class Builder {
final String mPackageName;
final int mSessionId;
- final String mControlCategory;
+ final String mRouteType;
String mProviderId;
final List<String> mSelectedRoutes;
final List<String> mSelectableRoutes;
@@ -300,11 +300,11 @@ public class RouteSessionInfo implements Parcelable {
Bundle mControlHints;
public Builder(int sessionId, @NonNull String packageName,
- @NonNull String controlCategory) {
+ @NonNull String routeType) {
mSessionId = sessionId;
mPackageName = Objects.requireNonNull(packageName, "packageName must not be null");
- mControlCategory = Objects.requireNonNull(controlCategory,
- "controlCategory must not be null");
+ mRouteType = Objects.requireNonNull(routeType,
+ "routeType must not be null");
mSelectedRoutes = new ArrayList<>();
mSelectableRoutes = new ArrayList<>();
@@ -315,7 +315,7 @@ public class RouteSessionInfo implements Parcelable {
public Builder(RouteSessionInfo sessionInfo) {
mSessionId = sessionInfo.mSessionId;
mPackageName = sessionInfo.mPackageName;
- mControlCategory = sessionInfo.mControlCategory;
+ mRouteType = sessionInfo.mRouteType;
mProviderId = sessionInfo.mProviderId;
mSelectedRoutes = new ArrayList<>(sessionInfo.mSelectedRoutes);
@@ -327,14 +327,30 @@ public class RouteSessionInfo implements Parcelable {
}
/**
- * Sets the provider id of the session.
+ * Sets the provider ID of the session.
+ * Also, calling this method will make all type of route IDs be unique by adding
+ * {@code providerId:} as a prefix. So do NOT call this method twice on same instance.
+ *
+ * @hide
*/
@NonNull
public Builder setProviderId(String providerId) {
mProviderId = providerId;
+ convertToUniqueRouteIds(providerId, mSelectedRoutes);
+ convertToUniqueRouteIds(providerId, mSelectableRoutes);
+ convertToUniqueRouteIds(providerId, mDeselectableRoutes);
+ convertToUniqueRouteIds(providerId, mTransferrableRoutes);
return this;
}
+ private void convertToUniqueRouteIds(@NonNull String providerId,
+ @NonNull List<String> routeIds) {
+ for (int i = 0; i < routeIds.size(); i++) {
+ String routeId = routeIds.get(i);
+ routeIds.set(i, MediaRoute2Info.toUniqueId(providerId, routeId));
+ }
+ }
+
/**
* Clears the selected routes.
*/
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index ab7bbca1d01c..4318a0ae7d06 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -62,6 +62,8 @@ public final class TvTrackInfo implements Parcelable {
private final int mAudioChannelCount;
private final int mAudioSampleRate;
private final boolean mAudioDescription;
+ private final boolean mHardOfHearing;
+ private final boolean mSpokenSubtitle;
private final int mVideoWidth;
private final int mVideoHeight;
private final float mVideoFrameRate;
@@ -72,8 +74,9 @@ public final class TvTrackInfo implements Parcelable {
private TvTrackInfo(int type, String id, String language, CharSequence description,
boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription,
- int videoWidth, int videoHeight, float videoFrameRate, float videoPixelAspectRatio,
- byte videoActiveFormatDescription, Bundle extra) {
+ boolean hardOfHearing, boolean spokenSubtitle, int videoWidth, int videoHeight,
+ float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription,
+ Bundle extra) {
mType = type;
mId = id;
mLanguage = language;
@@ -82,6 +85,8 @@ public final class TvTrackInfo implements Parcelable {
mAudioChannelCount = audioChannelCount;
mAudioSampleRate = audioSampleRate;
mAudioDescription = audioDescription;
+ mHardOfHearing = hardOfHearing;
+ mSpokenSubtitle = spokenSubtitle;
mVideoWidth = videoWidth;
mVideoHeight = videoHeight;
mVideoFrameRate = videoFrameRate;
@@ -99,6 +104,8 @@ public final class TvTrackInfo implements Parcelable {
mAudioChannelCount = in.readInt();
mAudioSampleRate = in.readInt();
mAudioDescription = in.readInt() != 0;
+ mHardOfHearing = in.readInt() != 0;
+ mSpokenSubtitle = in.readInt() != 0;
mVideoWidth = in.readInt();
mVideoHeight = in.readInt();
mVideoFrameRate = in.readFloat();
@@ -192,6 +199,39 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Returns {@code true} if the track is intended for people with hearing impairment, {@code
+ * false} otherwise. Valid only for {@link #TYPE_AUDIO} and {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language
+ * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468).
+ *
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ public boolean isHardOfHearing() {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio or a subtitle track");
+ }
+ return mHardOfHearing;
+ }
+
+ /**
+ * Returns {@code true} if the track is a spoken subtitle for people with visual impairment,
+ * {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks.
+ *
+ * <p>For example of broadcast, spoken subtitle information may be referred to broadcast
+ * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468).
+ *
+ * @throws IllegalStateException if not called on an audio track
+ */
+ public boolean isSpokenSubtitle() {
+ if (mType != TYPE_AUDIO) {
+ throw new IllegalStateException("Not an audio track");
+ }
+ return mSpokenSubtitle;
+ }
+
+ /**
* Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -287,6 +327,8 @@ public final class TvTrackInfo implements Parcelable {
dest.writeInt(mAudioChannelCount);
dest.writeInt(mAudioSampleRate);
dest.writeInt(mAudioDescription ? 1 : 0);
+ dest.writeInt(mHardOfHearing ? 1 : 0);
+ dest.writeInt(mSpokenSubtitle ? 1 : 0);
dest.writeInt(mVideoWidth);
dest.writeInt(mVideoHeight);
dest.writeFloat(mVideoFrameRate);
@@ -310,6 +352,7 @@ public final class TvTrackInfo implements Parcelable {
if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType
|| !TextUtils.equals(mLanguage, obj.mLanguage)
|| !TextUtils.equals(mDescription, obj.mDescription)
+ || mEncrypted != obj.mEncrypted
|| !Objects.equals(mExtra, obj.mExtra)) {
return false;
}
@@ -318,7 +361,9 @@ public final class TvTrackInfo implements Parcelable {
case TYPE_AUDIO:
return mAudioChannelCount == obj.mAudioChannelCount
&& mAudioSampleRate == obj.mAudioSampleRate
- && mAudioDescription == obj.mAudioDescription;
+ && mAudioDescription == obj.mAudioDescription
+ && mHardOfHearing == obj.mHardOfHearing
+ && mSpokenSubtitle == obj.mSpokenSubtitle;
case TYPE_VIDEO:
return mVideoWidth == obj.mVideoWidth
@@ -326,6 +371,9 @@ public final class TvTrackInfo implements Parcelable {
&& mVideoFrameRate == obj.mVideoFrameRate
&& mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio
&& mVideoActiveFormatDescription == obj.mVideoActiveFormatDescription;
+
+ case TYPE_SUBTITLE:
+ return mHardOfHearing == obj.mHardOfHearing;
}
return true;
@@ -361,6 +409,8 @@ public final class TvTrackInfo implements Parcelable {
private int mAudioChannelCount;
private int mAudioSampleRate;
private boolean mAudioDescription;
+ private boolean mHardOfHearing;
+ private boolean mSpokenSubtitle;
private int mVideoWidth;
private int mVideoHeight;
private float mVideoFrameRate;
@@ -474,6 +524,46 @@ public final class TvTrackInfo implements Parcelable {
}
/**
+ * Sets the hard of hearing attribute of the track. Valid only for {@link #TYPE_AUDIO} and
+ * {@link #TYPE_SUBTITLE} tracks.
+ *
+ * <p>For example of broadcast, hard of hearing information may be referred to broadcast
+ * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio
+ * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN
+ * 300 468).
+ *
+ * @param hardOfHearing The hard of hearing attribute of the track.
+ * @throws IllegalStateException if not called on an audio track or a subtitle track
+ */
+ @NonNull
+ public Builder setHardOfHearing(boolean hardOfHearing) {
+ if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) {
+ throw new IllegalStateException("Not an audio track or a subtitle track");
+ }
+ mHardOfHearing = hardOfHearing;
+ return this;
+ }
+
+ /**
+ * Sets the spoken subtitle attribute of the audio. Valid only for {@link #TYPE_AUDIO}
+ * tracks.
+ *
+ * <p>For example of broadcast, spoken subtitle information may be referred to broadcast
+ * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468).
+ *
+ * @param spokenSubtitle The spoken subtitle attribute of the audio.
+ * @throws IllegalStateException if not called on an audio track
+ */
+ @NonNull
+ public Builder setSpokenSubtitle(boolean spokenSubtitle) {
+ if (mType != TYPE_AUDIO) {
+ throw new IllegalStateException("Not an audio track");
+ }
+ mSpokenSubtitle = spokenSubtitle;
+ return this;
+ }
+
+ /**
* Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO}
* tracks.
*
@@ -575,9 +665,9 @@ public final class TvTrackInfo implements Parcelable {
*/
public TvTrackInfo build() {
return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted,
- mAudioChannelCount, mAudioSampleRate, mAudioDescription, mVideoWidth,
- mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio,
- mVideoActiveFormatDescription, mExtra);
+ mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing,
+ mSpokenSubtitle, mVideoWidth, mVideoHeight, mVideoFrameRate,
+ mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra);
}
}
}
diff --git a/media/java/android/media/tv/tuner/FilterConfiguration.java b/media/java/android/media/tv/tuner/FilterConfiguration.java
deleted file mode 100644
index b80a82a904b6..000000000000
--- a/media/java/android/media/tv/tuner/FilterConfiguration.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.tv.tuner;
-
-import android.annotation.Nullable;
-import android.media.tv.tuner.TunerConstants.FilterType;
-
-import java.util.List;
-
-/**
- * Demux Filter configuration.
- *
- * @hide
- */
-public abstract class FilterConfiguration {
- @Nullable
- protected final Settings mSettings;
-
- protected FilterConfiguration(Settings settings) {
- mSettings = settings;
- }
-
- /**
- * Gets filter configuration type
- */
- @FilterType
- public abstract int getType();
-
- public Settings getSettings() {
- return mSettings;
- }
-
- // TODO: more builders and getters
-
- /**
- * Filter configuration for a TS filter.
- */
- public static class TsFilterConfiguration extends FilterConfiguration {
- private int mTpid;
-
- private TsFilterConfiguration(Settings settings, int tpid) {
- super(settings);
- mTpid = tpid;
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_TS;
- }
-
- /**
- * Creates a new builder.
- */
- public static Builder newBuilder() {
- return new Builder();
- }
-
- /**
- * Builder for TsFilterConfiguration.
- */
- public static class Builder {
- private Settings mSettings;
- private int mTpid;
-
- /**
- * Sets settings.
- */
- public Builder setSettings(Settings settings) {
- mSettings = settings;
- return this;
- }
-
- /**
- * Sets TPID.
- */
- public Builder setTpid(int tpid) {
- mTpid = tpid;
- return this;
- }
-
- /**
- * Builds a TsFilterConfiguration instance.
- */
- public TsFilterConfiguration build() {
- return new TsFilterConfiguration(mSettings, mTpid);
- }
- }
- }
-
- /**
- * Filter configuration for a MMTP filter.
- */
- public static class MmtpFilterConfiguration extends FilterConfiguration {
- private int mMmtpPid;
-
- public MmtpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_MMTP;
- }
- }
-
-
- /**
- * Filter configuration for a IP filter.
- */
- public static class IpFilterConfiguration extends FilterConfiguration {
- private byte[] mSrcIpAddress;
- private byte[] mDstIpAddress;
- private int mSrcPort;
- private int mDstPort;
- private boolean mPassthrough;
-
- public IpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_IP;
- }
- }
-
-
- /**
- * Filter configuration for a TLV filter.
- */
- public static class TlvFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private boolean mIsCompressedIpPacket;
- private boolean mPassthrough;
-
- public TlvFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_TLV;
- }
- }
-
-
- /**
- * Filter configuration for a ALP filter.
- */
- public static class AlpFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private int mLengthType;
-
- public AlpFilterConfiguration(Settings settings) {
- super(settings);
- }
-
- @Override
- public int getType() {
- return TunerConstants.FILTER_TYPE_ALP;
- }
- }
-
-
- /**
- * Settings for filters of different subtypes.
- */
- public abstract static class Settings {
- protected final int mType;
-
- protected Settings(int type) {
- mType = type;
- }
-
- /**
- * Gets filter settings type.
- * @return
- */
- int getType() {
- return mType;
- }
- }
-
- /**
- * Filter Settings for Section data according to ISO/IEC 13818-1.
- */
- public static class SectionSettings extends Settings {
-
- private SectionSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_SECTION));
- }
- }
-
- /**
- * Bits Settings for Section Filter.
- */
- public static class SectionSettingsWithSectionBits extends SectionSettings {
- private List<Byte> mFilter;
- private List<Byte> mMask;
- private List<Byte> mMode;
-
- private SectionSettingsWithSectionBits(int mainType) {
- super(mainType);
- }
- }
-
- /**
- * Table information for Section Filter.
- */
- public static class SectionSettingsWithTableInfo extends SectionSettings {
- private int mTableId;
- private int mVersion;
-
- private SectionSettingsWithTableInfo(int mainType) {
- super(mainType);
- }
- }
-
- /**
- * Filter Settings for a PES Data.
- */
- public static class PesSettings extends Settings {
- private int mStreamId;
- private boolean mIsRaw;
-
- private PesSettings(int mainType, int streamId, boolean isRaw) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_PES));
- mStreamId = streamId;
- mIsRaw = isRaw;
- }
-
- /**
- * Creates a builder for PesSettings.
- */
- public static Builder newBuilder(int mainType) {
- return new Builder(mainType);
- }
-
- /**
- * Builder for PesSettings.
- */
- public static class Builder {
- private final int mMainType;
- private int mStreamId;
- private boolean mIsRaw;
-
- public Builder(int mainType) {
- mMainType = mainType;
- }
-
- /**
- * Sets stream ID.
- */
- public Builder setStreamId(int streamId) {
- mStreamId = streamId;
- return this;
- }
-
- /**
- * Sets whether it's raw.
- * true if the filter send onFilterStatus instead of onFilterEvent.
- */
- public Builder setIsRaw(boolean isRaw) {
- mIsRaw = isRaw;
- return this;
- }
-
- /**
- * Builds a PesSettings instance.
- */
- public PesSettings build() {
- return new PesSettings(mMainType, mStreamId, mIsRaw);
- }
- }
- }
-
- /**
- * Filter Settings for a Video and Audio.
- */
- public static class AvSettings extends Settings {
- private boolean mIsPassthrough;
-
- private AvSettings(int mainType, boolean isAudio) {
- super(TunerUtils.getFilterSubtype(
- mainType,
- isAudio
- ? TunerConstants.FILTER_SUBTYPE_AUDIO
- : TunerConstants.FILTER_SUBTYPE_VIDEO));
- }
- }
-
- /**
- * Filter Settings for a Download.
- */
- public static class DownloadSettings extends Settings {
- private int mDownloadId;
-
- public DownloadSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
- }
- }
-
- /**
- * The Settings for the record in DVR.
- */
- public static class RecordSettings extends Settings {
- private int mIndexType;
- private int mIndexMask;
-
- public RecordSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
- }
- }
-
-}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 43f9a8973e80..173551812f3a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.media.tv.tuner.FilterConfiguration.Settings;
import android.media.tv.tuner.TunerConstants.DemuxPidType;
import android.media.tv.tuner.TunerConstants.FilterStatus;
import android.media.tv.tuner.TunerConstants.FilterSubtype;
@@ -31,7 +30,9 @@ import android.media.tv.tuner.TunerConstants.LnbPosition;
import android.media.tv.tuner.TunerConstants.LnbTone;
import android.media.tv.tuner.TunerConstants.LnbVoltage;
import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.filter.FilterConfiguration;
import android.media.tv.tuner.filter.FilterEvent;
+import android.media.tv.tuner.filter.Settings;
import android.media.tv.tuner.frontend.FrontendCallback;
import android.media.tv.tuner.frontend.FrontendInfo;
import android.media.tv.tuner.frontend.FrontendStatus;
@@ -123,6 +124,7 @@ public final class Tuner implements AutoCloseable {
private native int nativeDisconnectCiCam();
private native FrontendInfo nativeGetFrontendInfo(int id);
private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+ private native TimeFilter nativeOpenTimeFilter();
private native List<Integer> nativeGetLnbIds();
private native Lnb nativeOpenLnbById(int id);
@@ -587,6 +589,127 @@ public final class Tuner implements AutoCloseable {
return filter;
}
+ /**
+ * A timer filter is used to filter data based on timestamps.
+ *
+ * <p> If the timestamp is set, data is discarded if its timestamp is smaller than the
+ * timestamp in this time filter.
+ *
+ * <p> The format of the timestamps is the same as PTS defined in ISO/IEC 13818-1:2019. The
+ * timestamps may or may not be related to PTS or DTS.
+ *
+ * @hide
+ */
+ public class TimeFilter {
+ private native int nativeSetTimestamp(long timestamp);
+ private native int nativeClearTimestamp();
+ private native Long nativeGetTimestamp();
+ private native Long nativeGetSourceTime();
+ private native int nativeClose();
+
+ private boolean mEnable = false;
+
+ /**
+ * Set timestamp for time based filter.
+ *
+ * It is used to set initial timestamp and enable time filtering. Once set, the time will be
+ * increased automatically like a clock. Contents are discarded if their timestamps are
+ * older than the time in the time filter.
+ *
+ * This method can be called more than once to reset the initial timestamp.
+ *
+ * @param timestamp initial timestamp for the time filter before it's increased. It's
+ * based on the 90KHz counter, and it's the same format as PTS (Presentation Time Stamp)
+ * defined in ISO/IEC 13818-1:2019. The timestamps may or may not be related to PTS or DTS.
+ * @return result status of the operation.
+ */
+ @Result
+ public int setCurrentTimestamp(long timestamp) {
+ int res = nativeSetTimestamp(timestamp);
+ // TODO: use a constant for SUCCESS
+ if (res == 0) {
+ mEnable = true;
+ }
+ return res;
+ }
+
+ /**
+ * Clear the timestamp in the time filter.
+ *
+ * It is used to clear the time value of the time filter. Time filtering is disabled then.
+ *
+ * @return result status of the operation.
+ */
+ @Result
+ public int clearTimestamp() {
+ int res = nativeClearTimestamp();
+ if (res == 0) {
+ mEnable = false;
+ }
+ return res;
+ }
+
+ /**
+ * Get the current time in the time filter.
+ *
+ * It is used to inquiry current time in the time filter.
+ *
+ * @return current timestamp in the time filter. It's based on the 90KHz counter, and it's
+ * the same format as PTS (Presentation Time Stamp) defined in ISO/IEC 13818-1:2019. The
+ * timestamps may or may not be related to PTS or DTS. {@code null} if the timestamp is
+ * never set.
+ */
+ @Nullable
+ public Long getTimeStamp() {
+ if (!mEnable) {
+ return null;
+ }
+ return nativeGetTimestamp();
+ }
+
+ /**
+ * Get the timestamp from the beginning of incoming data stream.
+ *
+ * It is used to inquiry the timestamp from the beginning of incoming data stream.
+ *
+ * @return first timestamp of incoming data stream. It's based on the 90KHz counter, and
+ * it's the same format as PTS (Presentation Time Stamp) defined in ISO/IEC 13818-1:2019.
+ * The timestamps may or may not be related to PTS or DTS.
+ */
+ @Nullable
+ public Long getSourceTime() {
+ if (!mEnable) {
+ return null;
+ }
+ return nativeGetSourceTime();
+ }
+
+ /**
+ * Close the Time Filter instance
+ *
+ * It is to release the TimeFilter instance. Resources are reclaimed so the instance must
+ * not be accessed after this method is called.
+ *
+ * @return result status of the operation.
+ */
+ @Result
+ public int close() {
+ return nativeClose();
+ }
+ }
+
+ /**
+ * Open a time filter instance.
+ *
+ * It is used to open time filter of demux.
+ *
+ * @return a time filter instance.
+ * @hide
+ */
+ public TimeFilter openTimeFilter() {
+ return nativeOpenTimeFilter();
+ }
+
/** @hide */
public class Lnb {
private int mId;
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index d24e582a8b21..e02443202085 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -227,41 +227,6 @@ public final class TunerConstants {
/** @hide */
public static final int FRONTEND_SCAN_BLIND = Constants.FrontendScanType.SCAN_BLIND;
- /** @hide */
- @IntDef({SCAN_MESSAGE_TYPE_LOCKED, SCAN_MESSAGE_TYPE_END, SCAN_MESSAGE_TYPE_PROGRESS_PERCENT,
- SCAN_MESSAGE_TYPE_FREQUENCY, SCAN_MESSAGE_TYPE_SYMBOL_RATE, SCAN_MESSAGE_TYPE_PLP_IDS,
- SCAN_MESSAGE_TYPE_GROUP_IDS, SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS,
- SCAN_MESSAGE_TYPE_STANDARD, SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScanMessageType {}
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_LOCKED = Constants.FrontendScanMessageType.LOCKED;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_END = Constants.FrontendScanMessageType.END;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_PROGRESS_PERCENT =
- Constants.FrontendScanMessageType.PROGRESS_PERCENT;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_FREQUENCY =
- Constants.FrontendScanMessageType.FREQUENCY;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_SYMBOL_RATE =
- Constants.FrontendScanMessageType.SYMBOL_RATE;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_GROUP_IDS =
- Constants.FrontendScanMessageType.GROUP_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS =
- Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_STANDARD =
- Constants.FrontendScanMessageType.STANDARD;
- /** @hide */
- public static final int SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO =
- Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
-
/** @hide */
@IntDef({FRONTEND_STATUS_TYPE_DEMOD_LOCK, FRONTEND_STATUS_TYPE_SNR, FRONTEND_STATUS_TYPE_BER,
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
new file mode 100644
index 000000000000..4d02b849899d
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Filter configuration for a ALP filter.
+ * @hide
+ */
+public class AlpFilterConfiguration extends FilterConfiguration {
+ private int mPacketType;
+ private int mLengthType;
+
+ public AlpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_TYPE_ALP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
new file mode 100644
index 000000000000..a7c49d5585f8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for a Video and Audio.
+ * @hide
+ */
+public class AvSettings extends Settings {
+ private boolean mIsPassthrough;
+
+ private AvSettings(int mainType, boolean isAudio) {
+ super(TunerUtils.getFilterSubtype(
+ mainType,
+ isAudio
+ ? TunerConstants.FILTER_SUBTYPE_AUDIO
+ : TunerConstants.FILTER_SUBTYPE_VIDEO));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
new file mode 100644
index 000000000000..0742b1166ede
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for a Download.
+ * @hide
+ */
+public class DownloadSettings extends Settings {
+ private int mDownloadId;
+
+ public DownloadSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
new file mode 100644
index 000000000000..930ca744a168
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.annotation.Nullable;
+import android.media.tv.tuner.TunerConstants.FilterType;
+
+/**
+ * Demux Filter configuration.
+ *
+ * @hide
+ */
+public abstract class FilterConfiguration {
+ @Nullable
+ protected final Settings mSettings;
+
+ protected FilterConfiguration(Settings settings) {
+ mSettings = settings;
+ }
+
+ /**
+ * Gets filter configuration type
+ */
+ @FilterType
+ public abstract int getType();
+
+ public Settings getSettings() {
+ return mSettings;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
new file mode 100644
index 000000000000..2c706c0ce9ce
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Filter configuration for a IP filter.
+ * @hide
+ */
+public class IpFilterConfiguration extends FilterConfiguration {
+ private byte[] mSrcIpAddress;
+ private byte[] mDstIpAddress;
+ private int mSrcPort;
+ private int mDstPort;
+ private boolean mPassthrough;
+
+ public IpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_TYPE_IP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
new file mode 100644
index 000000000000..f70e70a5bdb2
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Filter configuration for a MMTP filter.
+ * @hide
+ */
+public class MmtpFilterConfiguration extends FilterConfiguration {
+ private int mMmtpPid;
+
+ public MmtpFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_TYPE_MMTP;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/PesSettings.java b/media/java/android/media/tv/tuner/filter/PesSettings.java
new file mode 100644
index 000000000000..3d2c265cc00b
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/PesSettings.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for a PES Data.
+ * @hide
+ */
+public class PesSettings extends Settings {
+ private int mStreamId;
+ private boolean mIsRaw;
+
+ private PesSettings(int mainType, int streamId, boolean isRaw) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_PES));
+ mStreamId = streamId;
+ mIsRaw = isRaw;
+ }
+
+ /**
+ * Creates a builder for PesSettings.
+ */
+ public static Builder newBuilder(int mainType) {
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for PesSettings.
+ */
+ public static class Builder {
+ private final int mMainType;
+ private int mStreamId;
+ private boolean mIsRaw;
+
+ public Builder(int mainType) {
+ mMainType = mainType;
+ }
+
+ /**
+ * Sets stream ID.
+ */
+ public Builder setStreamId(int streamId) {
+ mStreamId = streamId;
+ return this;
+ }
+
+ /**
+ * Sets whether it's raw.
+ * true if the filter send onFilterStatus instead of onFilterEvent.
+ */
+ public Builder setIsRaw(boolean isRaw) {
+ mIsRaw = isRaw;
+ return this;
+ }
+
+ /**
+ * Builds a PesSettings instance.
+ */
+ public PesSettings build() {
+ return new PesSettings(mMainType, mStreamId, mIsRaw);
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
new file mode 100644
index 000000000000..701868afc789
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * The Settings for the record in DVR.
+ * @hide
+ */
+public class RecordSettings extends Settings {
+ private int mIndexType;
+ private int mIndexMask;
+
+ public RecordSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettings.java b/media/java/android/media/tv/tuner/filter/SectionSettings.java
new file mode 100644
index 000000000000..36e3d7cfee43
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettings.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerUtils;
+
+/**
+ * Filter Settings for Section data according to ISO/IEC 13818-1.
+ * @hide
+ */
+public class SectionSettings extends Settings {
+
+ SectionSettings(int mainType) {
+ super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_SECTION));
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
new file mode 100644
index 000000000000..414ea6790bf5
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import java.util.List;
+
+/**
+ * Bits Settings for Section Filter.
+ * @hide
+ */
+public class SectionSettingsWithSectionBits extends SectionSettings {
+ private List<Byte> mFilter;
+ private List<Byte> mMask;
+ private List<Byte> mMode;
+
+ private SectionSettingsWithSectionBits(int mainType) {
+ super(mainType);
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
new file mode 100644
index 000000000000..0df1d7308e60
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+/**
+ * Table information for Section Filter.
+ * @hide
+ */
+public class SectionSettingsWithTableInfo extends SectionSettings {
+ private int mTableId;
+ private int mVersion;
+
+ private SectionSettingsWithTableInfo(int mainType) {
+ super(mainType);
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java
new file mode 100644
index 000000000000..789ed0895750
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/Settings.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+/**
+ * Settings for filters of different subtypes.
+ * @hide
+ */
+public abstract class Settings {
+ protected final int mType;
+
+ protected Settings(int type) {
+ mType = type;
+ }
+
+ /**
+ * Gets filter settings type.
+ * @return
+ */
+ public int getType() {
+ return mType;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
new file mode 100644
index 000000000000..1f8bcb3b4a71
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Filter configuration for a TLV filter.
+ * @hide
+ */
+public class TlvFilterConfiguration extends FilterConfiguration {
+ private int mPacketType;
+ private boolean mIsCompressedIpPacket;
+ private boolean mPassthrough;
+
+ public TlvFilterConfiguration(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_TYPE_TLV;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
new file mode 100644
index 000000000000..103698cd0d75
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner.filter;
+
+import android.media.tv.tuner.TunerConstants;
+
+/**
+ * Filter configuration for a TS filter.
+ * @hide
+ */
+public class TsFilterConfiguration extends FilterConfiguration {
+ private int mTpid;
+
+ private TsFilterConfiguration(Settings settings, int tpid) {
+ super(settings);
+ mTpid = tpid;
+ }
+
+ @Override
+ public int getType() {
+ return TunerConstants.FILTER_TYPE_TS;
+ }
+
+ /**
+ * Creates a new builder.
+ */
+ public static TsFilterConfiguration.Builder newBuilder() {
+ return new TsFilterConfiguration.Builder();
+ }
+
+ /**
+ * Builder for TsFilterConfiguration.
+ */
+ public static class Builder {
+ private Settings mSettings;
+ private int mTpid;
+
+ /**
+ * Sets settings.
+ */
+ public TsFilterConfiguration.Builder setSettings(Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
+ * Sets TPID.
+ */
+ public TsFilterConfiguration.Builder setTpid(int tpid) {
+ mTpid = tpid;
+ return this;
+ }
+
+ /**
+ * Builds a TsFilterConfiguration instance.
+ */
+ public TsFilterConfiguration build() {
+ return new TsFilterConfiguration(mSettings, mTpid);
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
index 91776e17dc21..0992eb665330 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendCallback.java
@@ -16,8 +16,6 @@
package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.ScanMessage;
-
/**
* Frontend Callback.
*
diff --git a/media/java/android/media/tv/tuner/ScanMessage.java b/media/java/android/media/tv/tuner/frontend/ScanMessage.java
index 35f54f8447c0..dd687dd2959c 100644
--- a/media/java/android/media/tv/tuner/ScanMessage.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanMessage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-package android.media.tv.tuner;
+package android.media.tv.tuner.frontend;
-import android.media.tv.tuner.TunerConstants.ScanMessageType;
+import android.annotation.IntDef;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Message from frontend during scan operations.
@@ -24,6 +28,43 @@ import android.media.tv.tuner.TunerConstants.ScanMessageType;
* @hide
*/
public class ScanMessage {
+
+ /** @hide */
+ @IntDef({
+ LOCKED,
+ END,
+ PROGRESS_PERCENT,
+ FREQUENCY,
+ SYMBOL_RATE,
+ PLP_IDS,
+ GROUP_IDS,
+ INPUT_STREAM_IDS,
+ STANDARD,
+ ATSC3_PLP_INFO
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+ /** @hide */
+ public static final int LOCKED = Constants.FrontendScanMessageType.LOCKED;
+ /** @hide */
+ public static final int END = Constants.FrontendScanMessageType.END;
+ /** @hide */
+ public static final int PROGRESS_PERCENT = Constants.FrontendScanMessageType.PROGRESS_PERCENT;
+ /** @hide */
+ public static final int FREQUENCY = Constants.FrontendScanMessageType.FREQUENCY;
+ /** @hide */
+ public static final int SYMBOL_RATE = Constants.FrontendScanMessageType.SYMBOL_RATE;
+ /** @hide */
+ public static final int PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
+ /** @hide */
+ public static final int GROUP_IDS = Constants.FrontendScanMessageType.GROUP_IDS;
+ /** @hide */
+ public static final int INPUT_STREAM_IDS = Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
+ /** @hide */
+ public static final int STANDARD = Constants.FrontendScanMessageType.STANDARD;
+ /** @hide */
+ public static final int ATSC3_PLP_INFO = Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
+
private final int mType;
private final Object mValue;
@@ -33,69 +74,69 @@ public class ScanMessage {
}
/** Gets scan message type. */
- @ScanMessageType
+ @Type
public int getMessageType() {
return mType;
}
/** Message indicates whether frontend is locked or not. */
public boolean getIsLocked() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_LOCKED) {
+ if (mType != LOCKED) {
throw new IllegalStateException();
}
return (Boolean) mValue;
}
/** Message indicates whether the scan has reached the end or not. */
public boolean getIsEnd() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_END) {
+ if (mType != END) {
throw new IllegalStateException();
}
return (Boolean) mValue;
}
/** Progress message in percent. */
public int getProgressPercent() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PROGRESS_PERCENT) {
+ if (mType != PROGRESS_PERCENT) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets frequency. */
public int getFrequency() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_FREQUENCY) {
+ if (mType != FREQUENCY) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets symbol rate. */
public int getSymbolRate() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_SYMBOL_RATE) {
+ if (mType != SYMBOL_RATE) {
throw new IllegalStateException();
}
return (Integer) mValue;
}
/** Gets PLP IDs. */
public int[] getPlpIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PLP_IDS) {
+ if (mType != PLP_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets group IDs. */
public int[] getGroupIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_GROUP_IDS) {
+ if (mType != GROUP_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets Input stream IDs. */
public int[] getInputStreamIds() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS) {
+ if (mType != INPUT_STREAM_IDS) {
throw new IllegalStateException();
}
return (int[]) mValue;
}
/** Gets the DVB-T or DVB-S standard. */
public int getStandard() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_STANDARD) {
+ if (mType != STANDARD) {
throw new IllegalStateException();
}
return (int) mValue;
@@ -103,7 +144,7 @@ public class ScanMessage {
/** Gets PLP information for ATSC3. */
public Atsc3PlpInfo[] getAtsc3PlpInfos() {
- if (mType != TunerConstants.SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO) {
+ if (mType != ATSC3_PLP_INFO) {
throw new IllegalStateException();
}
return (Atsc3PlpInfo[]) mValue;
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index f0f368815d9d..4f1125f5e482 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -696,6 +696,10 @@ static jobject android_media_tv_Tuner_open_filter(
return tuner->openFilter(filterType, bufferSize);
}
+static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
+ return NULL;
+}
+
static DemuxFilterSettings getFilterSettings(
JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
DemuxFilterSettings filterSettings;
@@ -840,6 +844,28 @@ static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) {
return 0;
}
+// TODO: implement TimeFilter functions
+static int android_media_tv_Tuner_time_filter_set_timestamp(
+ JNIEnv, jobject, jlong) {
+ return 0;
+}
+
+static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) {
+ return 0;
+}
+
+static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) {
+ return NULL;
+}
+
+static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) {
+ return NULL;
+}
+
+static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) {
+ return 0;
+}
+
static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->openDescrambler();
@@ -1119,6 +1145,8 @@ static const JNINativeMethod gTunerMethods[] = {
(void *)android_media_tv_Tuner_get_frontend_info },
{ "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
(void *)android_media_tv_Tuner_open_filter },
+ { "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/Tuner$TimeFilter;",
+ (void *)android_media_tv_Tuner_open_time_filter },
{ "nativeGetLnbIds", "()Ljava/util/List;",
(void *)android_media_tv_Tuner_get_lnb_ids },
{ "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
@@ -1144,6 +1172,16 @@ static const JNINativeMethod gFilterMethods[] = {
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter },
};
+static const JNINativeMethod gTimeFilterMethods[] = {
+ { "nativeSetTimeStamp", "(J)I", (void *)android_media_tv_Tuner_time_filter_set_timestamp },
+ { "nativeClearTimeStamp", "()I", (void *)android_media_tv_Tuner_time_filter_clear_timestamp },
+ { "nativeGetTimeStamp", "()Ljava/lang/Long;",
+ (void *)android_media_tv_Tuner_time_filter_get_timestamp },
+ { "nativeGetSourceTime", "()Ljava/lang/Long;",
+ (void *)android_media_tv_Tuner_time_filter_get_source_time },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_time_filter_close },
+};
+
static const JNINativeMethod gDescramblerMethods[] = {
{ "nativeAddPid", "(IILandroid/media/tv/tuner/Tuner$Filter;)I",
(void *)android_media_tv_Tuner_add_pid },
@@ -1194,6 +1232,13 @@ static bool register_android_media_tv_Tuner(JNIEnv *env) {
return false;
}
if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/Tuner$TimeFilter",
+ gTimeFilterMethods,
+ NELEM(gTimeFilterMethods)) != JNI_OK) {
+ ALOGE("Failed to register time filter native methods");
+ return false;
+ }
+ if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/Tuner$Descrambler",
gDescramblerMethods,
NELEM(gDescramblerMethods)) != JNI_OK) {
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 04fccc7e0f94..ec177321bba3 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -46,8 +46,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to";
public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
- public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
- public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final String ROUTE_ID_SPECIAL_TYPE = "route_special_type";
+ public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route";
public static final int VOLUME_MAX = 100;
public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
@@ -58,10 +58,10 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
- public static final String CATEGORY_SAMPLE =
- "com.android.mediarouteprovider.CATEGORY_SAMPLE";
- public static final String CATEGORY_SPECIAL =
- "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+ public static final String TYPE_SAMPLE =
+ "com.android.mediarouteprovider.TYPE_SAMPLE";
+ public static final String TYPE_SPECIAL =
+ "com.android.mediarouteprovider.TYPE_SPECIAL";
Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
Map<String, Integer> mRouteSessionMap = new HashMap<>();
@@ -69,38 +69,38 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
private void initializeRoutes() {
MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setDeviceType(DEVICE_TYPE_TV)
.build();
MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setDeviceType(DEVICE_TYPE_SPEAKER)
.build();
MediaRoute2Info route3 = new MediaRoute2Info.Builder(
ROUTE_ID3_SESSION_CREATION_FAILED, ROUTE_NAME3)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info route4 = new MediaRoute2Info.Builder(
ROUTE_ID4_TO_SELECT_AND_DESELECT, ROUTE_NAME4)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info route5 = new MediaRoute2Info.Builder(
ROUTE_ID5_TO_TRANSFER_TO, ROUTE_NAME5)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.build();
MediaRoute2Info routeSpecial =
- new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_CATEGORY, ROUTE_NAME_SPECIAL_CATEGORY)
- .addSupportedCategory(CATEGORY_SAMPLE)
- .addSupportedCategory(CATEGORY_SPECIAL)
+ new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_TYPE, ROUTE_NAME_SPECIAL_TYPE)
+ .addRouteType(TYPE_SAMPLE)
+ .addRouteType(TYPE_SPECIAL)
.build();
MediaRoute2Info fixedVolumeRoute =
new MediaRoute2Info.Builder(ROUTE_ID_FIXED_VOLUME, ROUTE_NAME_FIXED_VOLUME)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_FIXED)
.build();
MediaRoute2Info variableVolumeRoute =
new MediaRoute2Info.Builder(ROUTE_ID_VARIABLE_VOLUME, ROUTE_NAME_VARIABLE_VOLUME)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.build();
@@ -167,7 +167,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onCreateSession(String packageName, String routeId, String controlCategory,
+ public void onCreateSession(String packageName, String routeId, String routeType,
long requestId) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
@@ -186,7 +186,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
mRouteSessionMap.put(routeId, sessionId);
RouteSessionInfo sessionInfo = new RouteSessionInfo.Builder(
- sessionId, packageName, controlCategory)
+ sessionId, packageName, routeType)
.addSelectedRoute(routeId)
.addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
.addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO)
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
index 6fe847bf5f3a..af69c7e8699f 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -23,18 +23,18 @@ import static android.media.MediaRoute2Info.DEVICE_TYPE_TV;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_ALL;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_SPECIAL;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SAMPLE;
-import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SPECIAL;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID1;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID2;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID3_SESSION_CREATION_FAILED;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID4_TO_SELECT_AND_DESELECT;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID5_TO_TRANSFER_TO;
-import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_CATEGORY;
+import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_TYPE;
import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME;
import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_ALL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_SPECIAL;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SAMPLE;
+import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SPECIAL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -50,6 +50,7 @@ import android.media.MediaRouter2;
import android.media.MediaRouter2.RouteCallback;
import android.media.MediaRouter2.RouteSessionController;
import android.media.MediaRouter2.SessionCallback;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.net.Uri;
import android.os.Parcel;
@@ -95,14 +96,14 @@ public class MediaRouter2Test {
}
/**
- * Tests if we get proper routes for application that has special control category.
+ * Tests if we get proper routes for application that has special route type.
*/
@Test
public void testGetRoutes() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_SPECIAL);
assertEquals(1, routes.size());
- assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE));
}
@Test
@@ -114,7 +115,7 @@ public class MediaRouter2Test {
.setIconUri(new Uri.Builder().path("icon").build())
.setVolume(5)
.setVolumeMax(20)
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
.setDeviceType(DEVICE_TYPE_SPEAKER)
.build();
@@ -137,7 +138,7 @@ public class MediaRouter2Test {
.setClientPackageName("com.android.mediaroutertest")
.setConnectionState(CONNECTION_STATE_CONNECTING)
.setIconUri(new Uri.Builder().path("icon").build())
- .addSupportedCategory(CATEGORY_SAMPLE)
+ .addRouteType(TYPE_SAMPLE)
.setVolume(5)
.setVolumeMax(20)
.setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
@@ -168,9 +169,9 @@ public class MediaRouter2Test {
.setClientPackageName("another.client.package").build();
assertNotEquals(route, routeClient);
- MediaRoute2Info routeCategory = new MediaRoute2Info.Builder(route)
- .addSupportedCategory(CATEGORY_SPECIAL).build();
- assertNotEquals(route, routeCategory);
+ MediaRoute2Info routeType = new MediaRoute2Info.Builder(route)
+ .addRouteType(TYPE_SPECIAL).build();
+ assertNotEquals(route, routeType);
MediaRoute2Info routeVolume = new MediaRoute2Info.Builder(route)
.setVolume(10).build();
@@ -191,7 +192,7 @@ public class MediaRouter2Test {
@Test
public void testControlVolumeWithRouter() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
assertNotNull(volRoute);
@@ -202,12 +203,14 @@ public class MediaRouter2Test {
awaitOnRouteChanged(
() -> mRouter2.requestUpdateVolume(volRoute, deltaVolume),
ROUTE_ID_VARIABLE_VOLUME,
- (route -> route.getVolume() == originalVolume + deltaVolume));
+ (route -> route.getVolume() == originalVolume + deltaVolume),
+ TYPES_ALL);
awaitOnRouteChanged(
() -> mRouter2.requestSetVolume(volRoute, originalVolume),
ROUTE_ID_VARIABLE_VOLUME,
- (route -> route.getVolume() == originalVolume));
+ (route -> route.getVolume() == originalVolume),
+ TYPES_ALL);
}
@Test
@@ -234,13 +237,13 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionWithInvalidArguments() {
MediaRoute2Info route = new MediaRoute2Info.Builder("id", "name").build();
- String controlCategory = "controlCategory";
+ String routeType = "routeType";
// Tests null route
assertThrows(NullPointerException.class,
- () -> mRouter2.requestCreateSession(null, controlCategory));
+ () -> mRouter2.requestCreateSession(null, routeType));
- // Tests null or empty control category
+ // Tests null or empty route type
assertThrows(IllegalArgumentException.class,
() -> mRouter2.requestCreateSession(route, null));
assertThrows(IllegalArgumentException.class,
@@ -249,10 +252,10 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionSuccess() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID1);
assertNotNull(route);
@@ -266,25 +269,25 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
successLatch.countDown();
}
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -298,10 +301,10 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionFailure() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID3_SESSION_CREATION_FAILED);
assertNotNull(route);
@@ -319,20 +322,20 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
assertEquals(route, requestedRoute);
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, requestedControlCategory));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, requestedRouteType));
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreated should not be called.
@@ -346,8 +349,8 @@ public class MediaRouter2Test {
@Test
public void testRequestCreateSessionMultipleSessions() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
final CountDownLatch successLatch = new CountDownLatch(2);
final CountDownLatch failureLatch = new CountDownLatch(1);
@@ -363,12 +366,12 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route1 = routes.get(ROUTE_ID1);
MediaRoute2Info route2 = routes.get(ROUTE_ID2);
assertNotNull(route1);
@@ -376,12 +379,12 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route1, CATEGORY_SAMPLE);
- mRouter2.requestCreateSession(route2, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route1, TYPE_SAMPLE);
+ mRouter2.requestCreateSession(route2, TYPE_SAMPLE);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -395,8 +398,8 @@ public class MediaRouter2Test {
assertNotEquals(controller1.getSessionId(), controller2.getSessionId());
assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(ROUTE_ID1));
assertTrue(createRouteMap(controller2.getSelectedRoutes()).containsKey(ROUTE_ID2));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller1.getControlCategory()));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller2.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller1.getRouteType()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller2.getRouteType()));
} finally {
releaseControllers(createdControllers);
mRouter2.unregisterRouteCallback(routeCallback);
@@ -406,10 +409,10 @@ public class MediaRouter2Test {
@Test
public void testSessionCallbackIsNotCalledAfterUnregistered() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info route = routes.get(ROUTE_ID1);
assertNotNull(route);
@@ -427,18 +430,18 @@ public class MediaRouter2Test {
@Override
public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedControlCategory) {
+ String requestedRouteType) {
failureLatch.countDown();
}
};
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(route, TYPE_SAMPLE);
// Unregisters session callback
mRouter2.unregisterSessionCallback(sessionCallback);
@@ -456,10 +459,10 @@ public class MediaRouter2Test {
// TODO: Add tests for illegal inputs if needed (e.g. selecting already selected route)
@Test
public void testRouteSessionControllerSelectAndDeselectRoute() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -474,7 +477,7 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -522,11 +525,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -554,10 +557,10 @@ public class MediaRouter2Test {
@Test
public void testRouteSessionControllerTransferToRoute() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -570,8 +573,12 @@ public class MediaRouter2Test {
@Override
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
+ android.util.Log.d(TAG, "selected route ids ");
+ for (String routeId : getRouteIds(controller.getSelectedRoutes())) {
+ android.util.Log.d(TAG, "route id : " + routeId);
+ }
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -603,11 +610,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -632,10 +639,10 @@ public class MediaRouter2Test {
@Test
public void testRouteSessionControllerReleaseShouldIgnoreTransferTo() throws Exception {
- final List<String> sampleControlCategory = new ArrayList<>();
- sampleControlCategory.add(CATEGORY_SAMPLE);
+ final List<String> sampleRouteType = new ArrayList<>();
+ sampleRouteType.add(TYPE_SAMPLE);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
assertNotNull(routeToCreateSessionWith);
@@ -649,7 +656,7 @@ public class MediaRouter2Test {
public void onSessionCreated(RouteSessionController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory()));
+ assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -667,11 +674,11 @@ public class MediaRouter2Test {
// TODO: Remove this once the MediaRouter2 becomes always connected to the service.
RouteCallback routeCallback = new RouteCallback();
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -701,17 +708,16 @@ public class MediaRouter2Test {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
}
- Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories)
+ Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes)
throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- // A dummy callback is required to send control category info.
+ // A dummy callback is required to send route type info.
RouteCallback routeCallback = new RouteCallback() {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
@@ -724,8 +730,8 @@ public class MediaRouter2Test {
}
};
- mRouter2.setControlCategories(controlCategories);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
return createRouteMap(mRouter2.getRoutes());
@@ -741,7 +747,7 @@ public class MediaRouter2Test {
}
/**
- * Returns a list of IDs (not uniqueId) of the given route list.
+ * Returns a list of IDs of the given route list.
*/
List<String> getRouteIds(@NonNull List<MediaRoute2Info> routes) {
List<String> result = new ArrayList<>();
@@ -752,7 +758,8 @@ public class MediaRouter2Test {
}
void awaitOnRouteChanged(Runnable task, String routeId,
- Predicate<MediaRoute2Info> predicate) throws Exception {
+ Predicate<MediaRoute2Info> predicate,
+ List<String> routeTypes) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
RouteCallback routeCallback = new RouteCallback() {
@Override
@@ -763,7 +770,8 @@ public class MediaRouter2Test {
}
}
};
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 83c7c173e8e8..c23a5b0d76e3 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -31,6 +31,7 @@ import android.media.MediaRouter2;
import android.media.MediaRouter2.RouteCallback;
import android.media.MediaRouter2.SessionCallback;
import android.media.MediaRouter2Manager;
+import android.media.RouteDiscoveryRequest;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -57,41 +58,48 @@ import java.util.function.Predicate;
public class MediaRouterManagerTest {
private static final String TAG = "MediaRouterManagerTest";
- // Must be the same as SampleMediaRoute2ProviderService
- public static final String ROUTE_ID1 = "route_id1";
+ public static final String SAMPLE_PROVIDER_ROUTES_ID_PREFIX =
+ "com.android.mediarouteprovider.example/.SampleMediaRoute2ProviderService:";
+
+ // Must be the same as SampleMediaRoute2ProviderService except the prefix of IDs.
+ public static final String ROUTE_ID1 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id1";
public static final String ROUTE_NAME1 = "Sample Route 1";
- public static final String ROUTE_ID2 = "route_id2";
+ public static final String ROUTE_ID2 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id2";
public static final String ROUTE_NAME2 = "Sample Route 2";
public static final String ROUTE_ID3_SESSION_CREATION_FAILED =
- "route_id3_session_creation_failed";
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id3_session_creation_failed";
public static final String ROUTE_NAME3 = "Sample Route 3 - Session creation failed";
public static final String ROUTE_ID4_TO_SELECT_AND_DESELECT =
- "route_id4_to_select_and_deselect";
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id4_to_select_and_deselect";
public static final String ROUTE_NAME4 = "Sample Route 4 - Route to select and deselect";
- public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to";
+ public static final String ROUTE_ID5_TO_TRANSFER_TO =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id5_to_transfer_to";
public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
- public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
- public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+ public static final String ROUTE_ID_SPECIAL_TYPE =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_special_type";
+ public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route";
public static final String SYSTEM_PROVIDER_ID =
"com.android.server.media/.SystemMediaRoute2Provider";
public static final int VOLUME_MAX = 100;
- public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
+ public static final String ROUTE_ID_FIXED_VOLUME =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_fixed_volume";
public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
- public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
+ public static final String ROUTE_ID_VARIABLE_VOLUME =
+ SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_variable_volume";
public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
- public static final String CATEGORY_SAMPLE =
- "com.android.mediarouteprovider.CATEGORY_SAMPLE";
- public static final String CATEGORY_SPECIAL =
- "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+ public static final String TYPE_SAMPLE =
+ "com.android.mediarouteprovider.TYPE_SAMPLE";
+ public static final String TYPE_SPECIAL =
+ "com.android.mediarouteprovider.TYPE_SPECIAL";
- private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+ private static final String TYPE_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
private static final int TIMEOUT_MS = 5000;
@@ -105,18 +113,18 @@ public class MediaRouterManagerTest {
private final List<RouteCallback> mRouteCallbacks = new ArrayList<>();
private final List<SessionCallback> mSessionCallbacks = new ArrayList<>();
- public static final List<String> CATEGORIES_ALL = new ArrayList();
- public static final List<String> CATEGORIES_SPECIAL = new ArrayList();
- private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+ public static final List<String> TYPES_ALL = new ArrayList();
+ public static final List<String> TYPES_SPECIAL = new ArrayList();
+ private static final List<String> TYPES_LIVE_AUDIO = new ArrayList<>();
static {
- CATEGORIES_ALL.add(CATEGORY_SAMPLE);
- CATEGORIES_ALL.add(CATEGORY_SPECIAL);
- CATEGORIES_ALL.add(CATEGORY_LIVE_AUDIO);
+ TYPES_ALL.add(TYPE_SAMPLE);
+ TYPES_ALL.add(TYPE_SPECIAL);
+ TYPES_ALL.add(TYPE_LIVE_AUDIO);
- CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL);
+ TYPES_SPECIAL.add(TYPE_SPECIAL);
- CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
+ TYPES_LIVE_AUDIO.add(TYPE_LIVE_AUDIO);
}
@Before
@@ -173,7 +181,7 @@ public class MediaRouterManagerTest {
@Test
public void testOnRoutesRemoved() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@@ -195,14 +203,14 @@ public class MediaRouterManagerTest {
}
/**
- * Tests if we get proper routes for application that has special control category.
+ * Tests if we get proper routes for application that has special route type.
*/
@Test
- public void testControlCategory() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
+ public void testRouteType() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_SPECIAL);
assertEquals(1, routes.size());
- assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE));
}
/**
@@ -211,7 +219,7 @@ public class MediaRouterManagerTest {
*/
@Test
public void testRouterOnSessionCreated() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
CountDownLatch latch = new CountDownLatch(1);
@@ -247,7 +255,7 @@ public class MediaRouterManagerTest {
@Ignore("TODO: test session created callback instead of onRouteSelected")
public void testManagerOnRouteSelected() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@@ -277,7 +285,7 @@ public class MediaRouterManagerTest {
public void testGetActiveRoutes() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
@@ -313,7 +321,7 @@ public class MediaRouterManagerTest {
@Test
@Ignore("TODO: enable when session is released")
public void testSingleProviderSelect() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
addRouterCallback(new RouteCallback());
awaitOnRouteChangedManager(
@@ -338,7 +346,7 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithManager() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
@@ -357,7 +365,7 @@ public class MediaRouterManagerTest {
@Test
public void testVolumeHandling() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL);
MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
@@ -367,11 +375,11 @@ public class MediaRouterManagerTest {
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
}
- Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> controlCategories)
+ Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeTypes)
throws Exception {
CountDownLatch latch = new CountDownLatch(2);
- // A dummy callback is required to send control category info.
+ // A dummy callback is required to send route type info.
RouteCallback routeCallback = new RouteCallback();
MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
@Override
@@ -386,16 +394,16 @@ public class MediaRouterManagerTest {
}
@Override
- public void onControlCategoriesChanged(String packageName, List<String> categories) {
+ public void onControlCategoriesChanged(String packageName, List<String> routeTypes) {
if (TextUtils.equals(mPackageName, packageName)
- && controlCategories.equals(categories)) {
+ && routeTypes.equals(routeTypes)) {
latch.countDown();
}
}
};
mManager.registerCallback(mExecutor, managerCallback);
- mRouter2.setControlCategories(controlCategories);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback,
+ new RouteDiscoveryRequest.Builder(routeTypes, true).build());
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
return createRouteMap(mManager.getAvailableRoutes(mPackageName));
@@ -430,7 +438,6 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
@@ -443,7 +450,7 @@ public class MediaRouterManagerTest {
private void addRouterCallback(RouteCallback routeCallback) {
mRouteCallbacks.add(routeCallback);
- mRouter2.registerRouteCallback(mExecutor, routeCallback);
+ mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY);
}
private void addSessionCallback(SessionCallback sessionCallback) {
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java
new file mode 100644
index 000000000000..60d131a8fb7e
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaroutertest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.media.RouteDiscoveryRequest;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteDiscoveryRequestTest {
+ @Before
+ public void setUp() throws Exception { }
+
+ @After
+ public void tearDown() throws Exception { }
+
+ @Test
+ public void testEquality() {
+ List<String> testTypes = new ArrayList<>();
+ testTypes.add("TEST_TYPE_1");
+ testTypes.add("TEST_TYPE_2");
+ RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true)
+ .build();
+
+ RouteDiscoveryRequest requestRebuilt = new RouteDiscoveryRequest.Builder(request)
+ .build();
+
+ assertEquals(request, requestRebuilt);
+
+ Parcel parcel = Parcel.obtain();
+ parcel.writeParcelable(request, 0);
+ parcel.setDataPosition(0);
+ RouteDiscoveryRequest requestFromParcel = parcel.readParcelable(null);
+
+ assertEquals(request, requestFromParcel);
+ }
+
+ @Test
+ public void testInequality() {
+ List<String> testTypes = new ArrayList<>();
+ testTypes.add("TEST_TYPE_1");
+ testTypes.add("TEST_TYPE_2");
+
+ List<String> testTypes2 = new ArrayList<>();
+ testTypes.add("TEST_TYPE_3");
+
+ RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true)
+ .build();
+
+ RouteDiscoveryRequest requestTypes = new RouteDiscoveryRequest.Builder(request)
+ .setRouteTypes(testTypes2)
+ .build();
+ assertNotEquals(request, requestTypes);
+
+ RouteDiscoveryRequest requestActiveScan = new RouteDiscoveryRequest.Builder(request)
+ .setActiveScan(false)
+ .build();
+ assertNotEquals(request, requestActiveScan);
+ }
+}
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index 65542673a607..24ea3cfc5a75 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -16,8 +16,11 @@
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.PendingIntent;
+import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
@@ -27,22 +30,16 @@ import com.android.internal.telephony.IMms;
/**
* Manages MMS operations such as sending multimedia messages.
- * Get this object by calling the static method {@link #getInstance()}.
- * @hide
*/
-public class MmsManager {
+public final class MmsManager {
private static final String TAG = "MmsManager";
-
- /** Singleton object constructed during class initialization. */
- private static final MmsManager sInstance = new MmsManager();
+ private final Context mContext;
/**
- * Get the MmsManager singleton instance.
- *
- * @return the {@link MmsManager} singleton instance.
+ * @hide
*/
- public static MmsManager getInstance() {
- return sInstance;
+ public MmsManager(@NonNull Context context) {
+ mContext = context;
}
/**
@@ -56,8 +53,9 @@ public class MmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message
* is successfully sent, or failed
*/
- public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl,
- Bundle configOverrides, PendingIntent sentIntent) {
+ public void sendMultimediaMessage(int subId, @NonNull Uri contentUri,
+ @Nullable String locationUrl, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent sentIntent) {
try {
final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
if (iMms == null) {
@@ -84,8 +82,9 @@ public class MmsManager {
* broadcast when the message is downloaded, or the download is failed
* @throws IllegalArgumentException if locationUrl or contentUri is empty
*/
- public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri,
- Bundle configOverrides, PendingIntent downloadedIntent) {
+ public void downloadMultimediaMessage(int subId, @NonNull String locationUrl,
+ @NonNull Uri contentUri, @Nullable Bundle configOverrides,
+ @Nullable PendingIntent downloadedIntent) {
try {
final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
if (iMms == null) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index ed945e7d4e72..f7802d205a3a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -18,6 +18,7 @@ package com.android.systemui.car;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -40,8 +41,9 @@ public class CarNotificationEntryManager extends NotificationEntryManager {
NotifLog notifLog,
NotificationGroupManager groupManager,
NotificationRankingManager rankingManager,
- KeyguardEnvironment keyguardEnvironment) {
- super(notifLog, groupManager, rankingManager, keyguardEnvironment);
+ KeyguardEnvironment keyguardEnvironment,
+ FeatureFlags featureFlags) {
+ super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags);
}
@Override
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 3c3ebe2fe228..1ee85188eac3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -110,6 +110,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
@@ -276,6 +277,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -363,6 +365,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
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 a1eccceea771..7108e65c8bce 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -70,6 +70,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -146,6 +147,7 @@ public class CarStatusBarModule {
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -232,6 +234,7 @@ public class CarStatusBarModule {
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 5b4ef3a47386..70b56ed0b391 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -194,6 +194,14 @@ public class LocalMediaManager implements BluetoothCallback {
}
}
+ void dispatchDeviceAttributesChanged() {
+ synchronized (mCallbacks) {
+ for (DeviceCallback callback : mCallbacks) {
+ callback.onDeviceAttributesChanged();
+ }
+ }
+ }
+
/**
* Stop scan MediaDevice
*/
@@ -306,14 +314,12 @@ public class LocalMediaManager implements BluetoothCallback {
}
mCurrentConnectedDevice = connectDevice;
updatePhoneMediaDeviceSummary();
- dispatchDeviceListUpdate();
+ dispatchDeviceAttributesChanged();
}
@Override
public void onDeviceAttributesChanged() {
- addPhoneDeviceIfNecessary();
- removePhoneMediaDeviceIfNecessary();
- dispatchDeviceListUpdate();
+ dispatchDeviceAttributesChanged();
}
}
@@ -327,7 +333,7 @@ public class LocalMediaManager implements BluetoothCallback {
*
* @param devices MediaDevice list
*/
- void onDeviceListUpdate(List<MediaDevice> devices);
+ default void onDeviceListUpdate(List<MediaDevice> devices) {};
/**
* Callback for notifying the connected device is changed.
@@ -338,6 +344,12 @@ public class LocalMediaManager implements BluetoothCallback {
* {@link MediaDeviceState#STATE_CONNECTING},
* {@link MediaDeviceState#STATE_DISCONNECTED}
*/
- void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state);
+ default void onSelectedDeviceStateChanged(MediaDevice device,
+ @MediaDeviceState int state) {};
+
+ /**
+ * Callback for notifying the device attributes is changed.
+ */
+ default void onDeviceAttributesChanged() {};
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 98bb74ad0718..894aa78a978e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -355,7 +355,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
- verify(mCallback).onDeviceListUpdate(any());
+ verify(mCallback).onDeviceAttributesChanged();
}
@Test
@@ -373,7 +373,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1);
- verify(mCallback, never()).onDeviceListUpdate(any());
+ verify(mCallback, never()).onDeviceAttributesChanged();
}
@Test
@@ -382,6 +382,6 @@ public class LocalMediaManagerTest {
mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
- verify(mCallback).onDeviceListUpdate(any());
+ verify(mCallback).onDeviceAttributesChanged();
}
}
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index f0ac08bdad37..982aa8ef6d16 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -18,7 +18,10 @@
<com.android.systemui.statusbar.notification.stack.PeopleHubView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="105dp">
+ android:layout_height="@dimen/notification_section_header_height"
+ android:focusable="true"
+ android:clickable="true"
+>
<com.android.systemui.statusbar.notification.row.NotificationBackgroundView
android:id="@+id/backgroundNormal"
@@ -34,199 +37,56 @@
android:id="@+id/people_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
android:gravity="center"
android:orientation="horizontal">
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginStart="@dimen/notification_section_header_padding_left"
+ android:gravity="start"
+ android:textAlignment="gravity"
+ android:text="@string/notification_section_header_conversations"
+ android:textSize="12sp"
+ android:textColor="@color/notification_section_header_label_color"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-
- <LinearLayout
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:visibility="invisible">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:scaleType="fitCenter"
- />
-
- <TextView
- android:id="@+id/person_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAlignment="center"
- />
-
- </LinearLayout>
-
- <View
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:padding="8dp"
+ android:scaleType="fitCenter"
/>
</LinearLayout>
@@ -236,4 +96,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-</com.android.systemui.statusbar.notification.stack.PeopleHubView> \ No newline at end of file
+</com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 52c0a26f09ba..4f532b7b751d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1163,6 +1163,9 @@
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
+ <!-- Section title for conversational notifications. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_conversations">Conversations</string>
+
<!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
<string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string>
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index eecc54c678c0..bbe972dea11f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -121,6 +121,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.DisplayImeController;
import com.android.systemui.wm.DisplayWindowController;
import com.android.systemui.wm.SystemWindows;
@@ -321,6 +322,7 @@ public class Dependency {
@Inject Lazy<StatusBar> mStatusBar;
@Inject Lazy<DisplayWindowController> mDisplayWindowController;
@Inject Lazy<SystemWindows> mSystemWindows;
+ @Inject Lazy<DisplayImeController> mDisplayImeController;
@Inject
public Dependency() {
@@ -509,6 +511,7 @@ public class Dependency {
mProviders.put(StatusBar.class, mStatusBar::get);
mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);
mProviders.put(SystemWindows.class, mSystemWindows::get);
+ mProviders.put(DisplayImeController.class, mDisplayImeController::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/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7cd29ea48199..d835ee1865bf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -344,11 +344,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mSavedBubbleKeysPerUser = new SparseSetArray<>();
mCurrentUserId = mNotifUserManager.getCurrentUserId();
mNotifUserManager.addUserChangedListener(
- newUserId -> {
- saveBubbles(mCurrentUserId);
- mBubbleData.dismissAll(DISMISS_USER_CHANGED);
- restoreBubbles(newUserId);
- mCurrentUserId = newUserId;
+ new NotificationLockscreenUserManager.UserChangedListener() {
+ @Override
+ public void onUserChanged(int newUserId) {
+ BubbleController.this.saveBubbles(mCurrentUserId);
+ mBubbleData.dismissAll(DISMISS_USER_CHANGED);
+ BubbleController.this.restoreBubbles(newUserId);
+ mCurrentUserId = newUserId;
+ }
});
mUserCreatedBubbles = new HashSet<>();
@@ -743,9 +746,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
return !isAutogroupSummary;
} else {
// If it's not a user dismiss it's a cancel.
+ for (int i = 0; i < bubbleChildren.size(); i++) {
+ // First check if any of these are user-created (i.e. experimental bubbles)
+ if (mUserCreatedBubbles.contains(bubbleChildren.get(i).getKey())) {
+ // Experimental bubble! Intercept the removal.
+ return true;
+ }
+ }
+ // Not an experimental bubble, safe to remove.
mBubbleData.removeSuppressedSummary(groupKey);
-
- // Remove any associated bubble children.
+ // Remove any associated bubble children with the summary.
for (int i = 0; i < bubbleChildren.size(); i++) {
Bubble bubbleChild = bubbleChildren.get(i);
mBubbleData.notificationEntryRemoved(bubbleChild.getEntry(),
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 8d10552332ba..53a23b89f943 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -20,7 +20,6 @@ import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import android.app.INotificationManager;
import android.content.Context;
-import android.content.pm.IPackageManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
@@ -115,13 +114,6 @@ public class DependencyProvider {
/** */
@Singleton
@Provides
- public IPackageManager provideIPackageManager() {
- return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- }
-
- /** */
- @Singleton
- @Provides
public LayoutInflater providerLayoutInflater(Context context) {
return LayoutInflater.from(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index bb12b53fec4c..26337b1f24b1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -27,6 +27,7 @@ import android.app.NotificationManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.IPackageManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
import android.os.Handler;
@@ -123,6 +124,13 @@ public class SystemServicesModule {
return WindowManagerGlobal.getWindowManagerService();
}
+ /** */
+ @Singleton
+ @Provides
+ public IPackageManager provideIPackageManager() {
+ return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ }
+
@Singleton
@Provides
static KeyguardManager provideKeyguardManager(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 2005d794c9d3..ac05c53c38dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -40,7 +40,7 @@ import javax.inject.Singleton;
* You will probably need to restart systemui for the changes to be picked up:
*
* {@code
- * $ adb shell am crash com.android.systemui
+ * $ adb shell am restart com.android.systemui
* }
*/
@Singleton
@@ -59,6 +59,11 @@ public class FeatureFlags {
return getDeviceConfigFlag("notification.newpipeline.enabled", false);
}
+ public boolean isNewNotifPipelineRenderingEnabled() {
+ return isNewNotifPipelineEnabled()
+ && getDeviceConfigFlag("notification.newpipeline.rendering", false);
+ }
+
private void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
synchronized (mCachedDeviceConfigFlags) {
for (String key : properties.getKeyset()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index ff4ce9492082..ebf7c2d58c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -49,6 +49,12 @@ public interface NotificationLockscreenUserManager {
/** Adds a listener to be notified when the current user changes. */
void addUserChangedListener(UserChangedListener listener);
+ /**
+ * Removes a listener previously registered with
+ * {@link #addUserChangedListener(UserChangedListener)}
+ */
+ void removeUserChangedListener(UserChangedListener listener);
+
SparseArray<UserInfo> getCurrentProfiles();
void setLockscreenPublicMode(boolean isProfilePublic, int userId);
@@ -79,6 +85,7 @@ public interface NotificationLockscreenUserManager {
/** Notified when the current user changes. */
interface UserChangedListener {
- void onUserChanged(int userId);
+ default void onUserChanged(int userId) {}
+ default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 2e369b3295b8..976531d8b49d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -117,51 +117,63 @@ public class NotificationLockscreenUserManagerImpl implements
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateCurrentProfilesCache();
- Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
- updateLockscreenNotificationSetting();
- 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().reapplyFilterAndSort("user switched");
- mPresenter.onUserSwitched(mCurrentUserId);
-
- for (UserChangedListener listener : mListeners) {
- listener.onUserChanged(mCurrentUserId);
- }
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateCurrentProfilesCache();
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- // Start the overview connection to the launcher service
- Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
- } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
- final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ mCurrentUserId = intent.getIntExtra(
+ Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
+ updateCurrentProfilesCache();
+
+ Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+ updateLockscreenNotificationSetting();
+ 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().reapplyFilterAndSort("user switched");
+ mPresenter.onUserSwitched(mCurrentUserId);
+
+ for (UserChangedListener listener : mListeners) {
+ listener.onUserChanged(mCurrentUserId);
}
- }
- if (notificationKey != null) {
- NotificationEntry entry =
- getEntryManager().getActiveNotificationUnfiltered(notificationKey);
- final int count = getEntryManager().getActiveNotificationsCount();
- final int rank = entry != null ? entry.getRanking().getRank() : 0;
- NotificationVisibility.NotificationLocation location =
- NotificationLogger.getNotificationLocation(entry);
- final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
- rank, count, true, location);
- try {
- mBarService.onNotificationClick(notificationKey, nv);
- } catch (RemoteException exception) {
- /* ignore */
+ break;
+ case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
+ case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
+ updateCurrentProfilesCache();
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+ break;
+ case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
+ final IntentSender intentSender = intent.getParcelableExtra(
+ Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
}
- }
+ if (notificationKey != null) {
+ NotificationEntry entry =
+ getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+ final int count = getEntryManager().getActiveNotificationsCount();
+ final int rank = entry != null ? entry.getRanking().getRank() : 0;
+ NotificationVisibility.NotificationLocation location =
+ NotificationLogger.getNotificationLocation(entry);
+ final NotificationVisibility nv = NotificationVisibility.obtain(
+ notificationKey,
+ rank, count, true, location);
+ try {
+ mBarService.onNotificationClick(notificationKey, nv);
+ } catch (RemoteException exception) {
+ /* ignore */
+ }
+ }
+ break;
}
}
};
@@ -266,6 +278,8 @@ public class NotificationLockscreenUserManagerImpl implements
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter);
IntentFilter internalFilter = new IntentFilter();
@@ -489,6 +503,11 @@ public class NotificationLockscreenUserManagerImpl implements
}
}
}
+ mMainHandler.post(() -> {
+ for (UserChangedListener listener : mListeners) {
+ listener.onCurrentProfilesChanged(mCurrentProfiles);
+ }
+ });
}
public boolean isAnyProfilePublicMode() {
@@ -555,6 +574,11 @@ public class NotificationLockscreenUserManagerImpl implements
mListeners.add(listener);
}
+ @Override
+ public void removeUserChangedListener(UserChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
// public void updatePublicMode() {
// //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
// // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 43d0399c6d62..667e721ae37d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -584,7 +584,15 @@ public class NotificationRemoteInputManager implements Dumpable {
public void bindRow(ExpandableNotificationRow row) {
row.setRemoteInputController(mRemoteInputController);
- row.setRemoteViewClickHandler(mOnClickHandler);
+ }
+
+ /**
+ * Return on-click handler for notification remote views
+ *
+ * @return on-click handler
+ */
+ public RemoteViews.OnClickHandler getRemoteViewsOnClickHandler() {
+ return mOnClickHandler;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
index d1f6ebf3826d..ec8dbead7de2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar;
import android.content.Context;
+import com.android.systemui.statusbar.notification.row.NotificationRowModule;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -26,7 +28,7 @@ import dagger.Provides;
/**
* Dagger Module providing common dependencies of StatusBar.
*/
-@Module
+@Module(includes = {NotificationRowModule.class})
public class StatusBarDependenciesModule {
/**
* Provides our instance of CommandQueue which is considered optional.
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 33d97a150048..a2578ab3cfa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -34,6 +34,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -131,6 +132,7 @@ public class NotificationEntryManager implements
private final KeyguardEnvironment mKeyguardEnvironment;
private final NotificationGroupManager mGroupManager;
private final NotificationRankingManager mRankingManager;
+ private final FeatureFlags mFeatureFlags;
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
@@ -170,11 +172,13 @@ public class NotificationEntryManager implements
NotifLog notifLog,
NotificationGroupManager groupManager,
NotificationRankingManager rankingManager,
- KeyguardEnvironment keyguardEnvironment) {
+ KeyguardEnvironment keyguardEnvironment,
+ FeatureFlags featureFlags) {
mNotifLog = notifLog;
mGroupManager = groupManager;
mRankingManager = rankingManager;
mKeyguardEnvironment = keyguardEnvironment;
+ mFeatureFlags = featureFlags;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -290,6 +294,10 @@ public class NotificationEntryManager implements
* WARNING: this will call back into us. Don't hold any locks.
*/
@Override
+ public void handleInflationException(NotificationEntry n, Exception e) {
+ handleInflationException(n.getSbn(), e);
+ }
+
public void handleInflationException(StatusBarNotification n, Exception e) {
removeNotificationInternal(
n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */,
@@ -529,9 +537,12 @@ public class NotificationEntryManager implements
NotificationEntry entry = new NotificationEntry(notification, ranking);
Dependency.get(LeakDetector.class).trackInstance(entry);
+
// Construct the expanded view.
- requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
- REASON_CANCEL));
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
+ REASON_CANCEL));
+ }
abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
@@ -574,8 +585,11 @@ public class NotificationEntryManager implements
listener.onPreEntryUpdated(entry);
}
- requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
- REASON_CANCEL));
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
+ REASON_CANCEL));
+ }
+
updateNotifications("updateNotificationInternal");
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 873cdbc91d25..856b75b7e36c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -299,6 +299,14 @@ public class NotifCollection {
if (!isLifetimeExtended(entry)) {
Ranking ranking = requireRanking(rankingMap, entry.getKey());
entry.setRanking(ranking);
+
+ // TODO: (b/145659174) update the sbn's overrideGroupKey in
+ // NotificationEntry.setRanking instead of here once we fully migrate to the
+ // NewNotifPipeline
+ final String newOverrideGroupKey = ranking.getOverrideGroupKey();
+ if (!Objects.equals(entry.getSbn().getOverrideGroupKey(), newOverrideGroupKey)) {
+ entry.getSbn().setOverrideGroupKey(newOverrideGroupKey);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
new file mode 100644
index 000000000000..fc04827a9d6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflater.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator;
+
+/**
+ * Used by the {@link PreparationCoordinator}. When notifications are added or updated, the
+ * NotifInflater is asked to (re)inflated and prepare their views. This inflation occurs off the
+ * main thread. When the inflation is finished, NotifInflater will trigger its InflationCallback.
+ */
+public interface NotifInflater {
+
+ /**
+ * Callback used when inflation is finished.
+ */
+ void setInflationCallback(InflationCallback callback);
+
+ /**
+ * Called to rebind the entry's views.
+ */
+ void rebindViews(NotificationEntry entry);
+
+ /**
+ * Called to inflate the views of an entry. Views are not considered inflated until all of its
+ * views are bound. Once all views are inflated, the InflationCallback is triggered.
+ */
+ void inflateViews(NotificationEntry entry);
+
+ /**
+ * Request to stop the inflation of an entry. For example, called when a notification is
+ * removed and no longer needs to be inflated.
+ */
+ void abortInflation(NotificationEntry entry);
+
+ /**
+ * Callback once all the views are inflated and bound for a given NotificationEntry.
+ */
+ interface InflationCallback {
+ void onInflationFinished(NotificationEntry entry);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
new file mode 100644
index 000000000000..0d175574f16b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.os.RemoteException;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles notification inflating, rebinding, and inflation aborting.
+ *
+ * Currently a wrapper for NotificationRowBinderImpl.
+ */
+@Singleton
+public class NotifInflaterImpl implements NotifInflater {
+
+ private final IStatusBarService mStatusBarService;
+ private final NotifCollection mNotifCollection;
+
+ private NotificationRowBinderImpl mNotificationRowBinder;
+ private InflationCallback mExternalInflationCallback;
+
+ @Inject
+ public NotifInflaterImpl(
+ IStatusBarService statusBarService,
+ NotifCollection notifCollection) {
+ mStatusBarService = statusBarService;
+ mNotifCollection = notifCollection;
+ }
+
+ /**
+ * Attaches the row binder for inflation.
+ */
+ public void setRowBinder(NotificationRowBinderImpl rowBinder) {
+ mNotificationRowBinder = rowBinder;
+ mNotificationRowBinder.setInflationCallback(mInflationCallback);
+ }
+
+ @Override
+ public void setInflationCallback(InflationCallback callback) {
+ mExternalInflationCallback = callback;
+ }
+
+ @Override
+ public void rebindViews(NotificationEntry entry) {
+ inflateViews(entry);
+ }
+
+ /**
+ * Called to inflate the views of an entry. Views are not considered inflated until all of its
+ * views are bound.
+ */
+ @Override
+ public void inflateViews(NotificationEntry entry) {
+ try {
+ entry.setHasInflationError(false);
+ requireBinder().inflateViews(entry, getDismissCallback(entry));
+ } catch (InflationException e) {
+ // logged in mInflationCallback.handleInflationException
+ }
+ }
+
+ @Override
+ public void abortInflation(NotificationEntry entry) {
+ entry.abortTask();
+ }
+
+ private Runnable getDismissCallback(NotificationEntry entry) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ /**
+ * TODO: determine dismissal surface (ie: shade / headsup / aod)
+ * see {@link NotificationLogger#logNotificationClear}
+ */
+ mNotifCollection.dismissNotification(
+ entry,
+ 0,
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotifCollection.getNotifs().size(),
+ true,
+ NotificationLogger.getNotificationLocation(entry))
+ ));
+ }
+ };
+ }
+
+ private NotificationRowBinderImpl requireBinder() {
+ if (mNotificationRowBinder == null) {
+ throw new RuntimeException("NotificationRowBinder must be attached before using "
+ + "NotifInflaterImpl.");
+ }
+ return mNotificationRowBinder;
+ }
+
+ private final NotificationContentInflater.InflationCallback mInflationCallback =
+ new NotificationContentInflater.InflationCallback() {
+ @Override
+ public void handleInflationException(
+ NotificationEntry entry,
+ Exception e) {
+ entry.setHasInflationError(true);
+ try {
+ final StatusBarNotification sbn = entry.getSbn();
+ // report notification inflation errors back up
+ // to notification delegates
+ mStatusBarService.onNotificationError(
+ sbn.getPackageName(),
+ sbn.getTag(),
+ sbn.getId(),
+ sbn.getUid(),
+ sbn.getInitialPid(),
+ e.getMessage(),
+ sbn.getUserId());
+ } catch (RemoteException ex) {
+ }
+ }
+
+ @Override
+ public void onAsyncInflationFinished(
+ NotificationEntry entry,
+ int inflatedFlags) {
+ if (mExternalInflationCallback != null) {
+ mExternalInflationCallback.onInflationFinished(entry);
+ }
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 4f4fb240162d..28e486df29b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -102,6 +102,9 @@ public final class NotificationEntry extends ListEntry {
/** If this was a group child that was promoted to the top level, then who did the promoting. */
@Nullable NotifPromoter mNotifPromoter;
+ /** If this notification had an issue with inflating. Only used with the NewNotifPipeline **/
+ private boolean mHasInflationError;
+
/*
* Old members
@@ -576,6 +579,18 @@ public final class NotificationEntry extends ListEntry {
remoteInputTextWhenReset = null;
}
+ void setHasInflationError(boolean hasError) {
+ mHasInflationError = hasError;
+ }
+
+ /**
+ * Whether this notification had an error when attempting to inflate. This is only used in
+ * the NewNotifPipeline
+ */
+ public boolean hasInflationError() {
+ return mHasInflationError;
+ }
+
public void setHasSentReply() {
hasSentReply = true;
}
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 6c93618e5395..20f206b91f10 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
@@ -41,8 +41,8 @@ import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -65,6 +65,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
Dependency.get(NotificationInterruptionStateProvider.class);
private final Context mContext;
+ private final NotificationRowContentBinder mRowContentBinder;
private final NotificationMessagingUtil mMessagingUtil;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -76,7 +77,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
private HeadsUpManager mHeadsUpManager;
- private NotificationContentInflater.InflationCallback mInflationCallback;
+ private NotificationRowContentBinder.InflationCallback mInflationCallback;
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
@@ -84,11 +85,13 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
public NotificationRowBinderImpl(
Context context,
+ NotificationRowContentBinder rowContentBinder,
boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
StatusBarStateController statusBarStateController,
NotificationLogger logger) {
mContext = context;
+ mRowContentBinder = rowContentBinder;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
@@ -109,16 +112,18 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer,
HeadsUpManager headsUpManager,
- NotificationContentInflater.InflationCallback inflationCallback,
BindRowCallback bindRowCallback) {
mPresenter = presenter;
mListContainer = listContainer;
mHeadsUpManager = headsUpManager;
- mInflationCallback = inflationCallback;
mBindRowCallback = bindRowCallback;
mOnAppOpsClickListener = mGutsManager::openGuts;
}
+ public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) {
+ mInflationCallback = callback;
+ }
+
public void setNotificationClicker(NotificationClicker clicker) {
mNotificationClicker = clicker;
}
@@ -154,19 +159,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private void bindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row,
Runnable onDismissRunnable) {
- row.setExpansionLogger(mExpansionLogger, entry.getSbn().getKey());
- row.setBypassController(mKeyguardBypassController);
- row.setStatusBarStateController(mStatusBarStateController);
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setOnExpandClickListener(mPresenter);
- row.setInflationCallback(mInflationCallback);
- if (mAllowLongPress) {
- row.setLongPressListener(mGutsManager::openGuts);
- }
- mListContainer.bindRow(row);
- getRemoteInputManager().bindRow(row);
-
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
// but since this field is used in the guts, it must be accurate.
@@ -184,15 +176,33 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
} catch (PackageManager.NameNotFoundException e) {
// Do nothing
}
- row.setAppName(appname);
+
+ row.initialize(
+ appname,
+ sbn.getKey(),
+ mExpansionLogger,
+ mKeyguardBypassController,
+ mGroupManager,
+ mHeadsUpManager,
+ mRowContentBinder,
+ mPresenter);
+
+ // TODO: Either move these into ExpandableNotificationRow#initialize or out of row entirely
+ row.setStatusBarStateController(mStatusBarStateController);
+ row.setInflationCallback(mInflationCallback);
+ row.setAppOpsOnClickListener(mOnAppOpsClickListener);
+ if (mAllowLongPress) {
+ row.setLongPressListener(mGutsManager::openGuts);
+ }
+ mListContainer.bindRow(row);
+ getRemoteInputManager().bindRow(row);
+
row.setOnDismissRunnable(onDismissRunnable);
row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (ENABLE_REMOTE_INPUT) {
row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
- row.setAppOpsOnClickListener(mOnAppOpsClickListener);
-
mBindRowCallback.onBindRow(entry, pmUser, sbn, row);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 132471933bb2..eeb54abf92b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
@@ -45,14 +46,19 @@ public class NotifCoordinators implements Dumpable {
*/
@Inject
public NotifCoordinators(
+ FeatureFlags featureFlags,
KeyguardCoordinator keyguardCoordinator,
RankingCoordinator rankingCoordinator,
ForegroundCoordinator foregroundCoordinator,
- DeviceProvisionedCoordinator deviceProvisionedCoordinator) {
+ DeviceProvisionedCoordinator deviceProvisionedCoordinator,
+ PreparationCoordinator preparationCoordinator) {
mCoordinators.add(keyguardCoordinator);
mCoordinators.add(rankingCoordinator);
mCoordinators.add(foregroundCoordinator);
mCoordinators.add(deviceProvisionedCoordinator);
+ if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mCoordinators.add(preparationCoordinator);
+ }
// TODO: add new Coordinators here! (b/145134683, b/112656837)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
new file mode 100644
index 000000000000..a14f0e1cf631
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifInflater;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Kicks off notification inflation and view rebinding when a notification is added or updated.
+ * Aborts inflation when a notification is removed.
+ *
+ * If a notification is not done inflating, this coordinator will filter the notification out
+ * from the NotifListBuilder.
+ */
+@Singleton
+public class PreparationCoordinator implements Coordinator {
+ private static final String TAG = "PreparationCoordinator";
+
+ private final NotifLog mNotifLog;
+ private final NotifInflater mNotifInflater;
+ private final List<NotificationEntry> mPendingNotifications = new ArrayList<>();
+
+ @Inject
+ public PreparationCoordinator(NotifLog notifLog, NotifInflaterImpl notifInflater) {
+ mNotifLog = notifLog;
+ mNotifInflater = notifInflater;
+ mNotifInflater.setInflationCallback(mInflationCallback);
+ }
+
+ @Override
+ public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+ notifCollection.addCollectionListener(mNotifCollectionListener);
+ notifListBuilder.addPreRenderFilter(mNotifInflationErrorFilter);
+ notifListBuilder.addPreRenderFilter(mNotifInflatingFilter);
+ }
+
+ private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
+ @Override
+ public void onEntryAdded(NotificationEntry entry) {
+ inflateEntry(entry, "entryAdded");
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationEntry entry) {
+ rebind(entry, "entryUpdated");
+ }
+
+ @Override
+ public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+ abortInflation(entry, "entryRemoved reason=" + reason);
+ }
+ };
+
+ private final NotifFilter mNotifInflationErrorFilter = new NotifFilter(
+ TAG + "InflationError") {
+ /**
+ * Filters out notifications that threw an error when attempting to inflate.
+ */
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ if (entry.hasInflationError()) {
+ mPendingNotifications.remove(entry);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ private final NotifFilter mNotifInflatingFilter = new NotifFilter(TAG + "Inflating") {
+ /**
+ * Filters out notifications that haven't been inflated yet
+ */
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return mPendingNotifications.contains(entry);
+ }
+ };
+
+ private final NotifInflater.InflationCallback mInflationCallback =
+ new NotifInflater.InflationCallback() {
+ @Override
+ public void onInflationFinished(NotificationEntry entry) {
+ mNotifLog.log(NotifEvent.INFLATED, entry);
+ mPendingNotifications.remove(entry);
+ mNotifInflatingFilter.invalidateList();
+ }
+ };
+
+ private void inflateEntry(NotificationEntry entry, String reason) {
+ abortInflation(entry, reason);
+ mPendingNotifications.add(entry);
+ mNotifInflater.inflateViews(entry);
+ }
+
+ private void rebind(NotificationEntry entry, String reason) {
+ mNotifInflater.rebindViews(entry);
+ }
+
+ private void abortInflation(NotificationEntry entry, String reason) {
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, reason);
+ entry.abortTask();
+ mPendingNotifications.remove(entry);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 5e0bd4fdcf23..8d3d0ff43deb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -20,9 +20,12 @@ import android.util.Log;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
@@ -41,7 +44,9 @@ public class NewNotifPipeline implements Dumpable {
private final NotifCollection mNotifCollection;
private final NotifListBuilderImpl mNotifPipeline;
private final NotifCoordinators mNotifPluggableCoordinators;
+ private final NotifInflaterImpl mNotifInflater;
private final DumpController mDumpController;
+ private final FeatureFlags mFeatureFlags;
private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
@@ -51,20 +56,30 @@ public class NewNotifPipeline implements Dumpable {
NotifCollection notifCollection,
NotifListBuilderImpl notifPipeline,
NotifCoordinators notifCoordinators,
- DumpController dumpController) {
+ NotifInflaterImpl notifInflater,
+ DumpController dumpController,
+ FeatureFlags featureFlags) {
mGroupCoalescer = groupCoalescer;
mNotifCollection = notifCollection;
mNotifPipeline = notifPipeline;
mNotifPluggableCoordinators = notifCoordinators;
mDumpController = dumpController;
+ mNotifInflater = notifInflater;
+ mFeatureFlags = featureFlags;
}
/** Hooks the new pipeline up to NotificationManager */
public void initialize(
- NotificationListener notificationService) {
+ NotificationListener notificationService,
+ NotificationRowBinderImpl rowBinder) {
mDumpController.registerDumpable("NotifPipeline", this);
+ // Setup inflation
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mNotifInflater.setRowBinder(rowBinder);
+ }
+
// Wire up coordinators
mFakePipelineConsumer.attach(mNotifPipeline);
mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
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 3e1b5bd0571e..89e5f5596291 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
@@ -294,6 +294,9 @@ public class NotificationLogger implements StateListener {
}
}
+ /**
+ * Logs Notification inflation error
+ */
private void logNotificationError(
StatusBarNotification notification,
Exception exception) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
index 2c0c9420a8c4..e81d361f58f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
@@ -37,7 +37,8 @@ data class PersonModel(
val key: PersonKey,
val name: CharSequence,
val avatar: Drawable,
- val clickIntent: PendingIntent
+ val clickIntent: PendingIntent,
+ val userId: Int
)
/** Unique identifier for a Person in PeopleHub. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index 784673e64ff8..88b41471a063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -17,28 +17,27 @@
package com.android.systemui.statusbar.notification.people
import android.app.Notification
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.ColorFilter
-import android.graphics.PixelFormat
-import android.graphics.drawable.BitmapDrawable
+import android.content.pm.UserInfo
import android.graphics.drawable.Drawable
-import android.os.UserHandle
+import android.os.UserManager
import android.service.notification.StatusBarNotification
-import android.util.TypedValue
+import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.android.internal.statusbar.NotificationVisibility
import com.android.internal.widget.MessagingGroup
-import com.android.launcher3.icons.BaseIconFactory
import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.NotificationPersonExtractorPlugin
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.NotificationEntryListener
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.policy.ExtensionController
import java.util.ArrayDeque
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
@@ -52,8 +51,7 @@ interface NotificationPersonExtractor {
@Singleton
class NotificationPersonExtractorPluginBoundary @Inject constructor(
- extensionController: ExtensionController,
- private val context: Context
+ extensionController: ExtensionController
) : NotificationPersonExtractor {
private var plugin: NotificationPersonExtractorPlugin? = null
@@ -70,9 +68,8 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
}
override fun extractPerson(sbn: StatusBarNotification) =
- plugin?.extractPerson(sbn)?.let { data ->
- val badged = addBadgeToDrawable(data.avatar, context, sbn.packageName, sbn.user)
- PersonModel(data.key, data.name, badged, data.clickIntent)
+ plugin?.extractPerson(sbn)?.run {
+ PersonModel(key, name, avatar, clickIntent, sbn.user.identifier)
}
override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
@@ -84,11 +81,16 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
@Singleton
class PeopleHubDataSourceImpl @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
- private val peopleHubManager: PeopleHubManager,
- private val extractor: NotificationPersonExtractor
+ private val extractor: NotificationPersonExtractor,
+ private val userManager: UserManager,
+ @Background private val bgExecutor: Executor,
+ @Main private val mainExecutor: Executor,
+ private val notifLockscreenUserMgr: NotificationLockscreenUserManager
) : DataSource<PeopleHubModel> {
+ private var userChangeSubscription: Subscription? = null
private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
+ private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
private val notificationEntryListener = object : NotificationEntryListener {
override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
@@ -106,31 +108,56 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
private fun removeVisibleEntry(entry: NotificationEntry) {
- val key = extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey()
- if (key?.let(peopleHubManager::removeActivePerson) == true) {
- updateUi()
+ (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) {
+ updateUi()
+ }
+ }
+ }
}
}
private fun addVisibleEntry(entry: NotificationEntry) {
- val personModel = extractor.extractPerson(entry.sbn) ?: entry.extractPerson()
- if (personModel?.let(peopleHubManager::addActivePerson) == true) {
- updateUi()
+ (extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel ->
+ val userId = entry.sbn.user.identifier
+ bgExecutor.execute {
+ val parentId = userManager.getProfileParent(userId)?.id ?: userId
+ mainExecutor.execute {
+ val manager = peopleHubManagerForUser[parentId]
+ ?: PeopleHubManager().also { peopleHubManagerForUser.put(parentId, it) }
+ if (manager.addActivePerson(personModel)) {
+ updateUi()
+ }
+ }
+ }
}
}
override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
- val registerWithNotificationEntryManager = dataListeners.isEmpty()
+ val register = dataListeners.isEmpty()
dataListeners.add(listener)
- if (registerWithNotificationEntryManager) {
+ if (register) {
+ userChangeSubscription = notifLockscreenUserMgr.registerListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) = updateUi()
+ override fun onCurrentProfilesChanged(
+ currentProfiles: SparseArray<UserInfo>?
+ ) = updateUi()
+ })
notificationEntryManager.addNotificationEntryListener(notificationEntryListener)
} else {
- listener.onDataChanged(peopleHubManager.getPeopleHubModel())
+ getPeopleHubModelForCurrentUser()?.let(listener::onDataChanged)
}
return object : Subscription {
override fun unsubscribe() {
dataListeners.remove(listener)
if (dataListeners.isEmpty()) {
+ userChangeSubscription?.unsubscribe()
+ userChangeSubscription = null
notificationEntryManager
.removeNotificationEntryListener(notificationEntryListener)
}
@@ -138,16 +165,36 @@ class PeopleHubDataSourceImpl @Inject constructor(
}
}
+ private fun getPeopleHubModelForCurrentUser(): PeopleHubModel? {
+ val currentUserId = notifLockscreenUserMgr.currentUserId
+ val model = peopleHubManagerForUser[currentUserId]?.getPeopleHubModel()
+ ?: return null
+ val currentProfiles = notifLockscreenUserMgr.currentProfiles
+ return model.copy(people = model.people.filter { person ->
+ currentProfiles[person.userId]?.isQuietModeEnabled == false
+ })
+ }
+
private fun updateUi() {
- val model = peopleHubManager.getPeopleHubModel()
+ val model = getPeopleHubModelForCurrentUser() ?: return
for (listener in dataListeners) {
listener.onDataChanged(model)
}
}
}
-@Singleton
-class PeopleHubManager @Inject constructor() {
+private fun NotificationLockscreenUserManager.registerListener(
+ listener: NotificationLockscreenUserManager.UserChangedListener
+): Subscription {
+ addUserChangedListener(listener)
+ return object : Subscription {
+ override fun unsubscribe() {
+ removeUserChangedListener(listener)
+ }
+ }
+}
+
+class PeopleHubManager {
private val activePeople = mutableMapOf<PersonKey, PersonModel>()
private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
@@ -157,7 +204,7 @@ class PeopleHubManager @Inject constructor() {
if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) {
inactivePeople.removeLast()
}
- inactivePeople.push(data)
+ inactivePeople.add(data)
return true
}
return false
@@ -190,63 +237,7 @@ private fun NotificationEntry.extractPerson(): PersonModel? {
?: extras.getString(Notification.EXTRA_TITLE)
?: return null
val drawable = extractAvatarFromRow(this) ?: return null
- val badgedAvatar = addBadgeToDrawable(drawable, row.context, sbn.packageName, sbn.user)
- return PersonModel(key, name, badgedAvatar, clickIntent)
-}
-
-private fun addBadgeToDrawable(
- drawable: Drawable,
- context: Context,
- packageName: String,
- user: UserHandle
-): Drawable {
- val pm = context.packageManager
- val appInfo = pm.getApplicationInfoAsUser(packageName, 0, user)
- return object : Drawable() {
- override fun draw(canvas: Canvas) {
- val iconBounds = getBounds()
- val factory = object : BaseIconFactory(
- context,
- 0 /* unused */,
- iconBounds.width(),
- true) {}
- val badge = factory.createBadgedIconBitmap(
- appInfo.loadIcon(pm),
- user,
- true,
- appInfo.isInstantApp,
- null)
- val badgeDrawable = BitmapDrawable(context.resources, badge.icon)
- .apply {
- alpha = drawable.alpha
- colorFilter = drawable.colorFilter
- val badgeWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 15f,
- context.resources.displayMetrics
- ).toInt()
- setBounds(
- iconBounds.left + (iconBounds.width() - badgeWidth),
- iconBounds.top + (iconBounds.height() - badgeWidth),
- iconBounds.right,
- iconBounds.bottom)
- }
- drawable.bounds = iconBounds
- drawable.draw(canvas)
- badgeDrawable.draw(canvas)
- }
-
- override fun setAlpha(alpha: Int) {
- drawable.alpha = alpha
- }
-
- override fun setColorFilter(colorFilter: ColorFilter?) {
- drawable.colorFilter = colorFilter
- }
-
- @PixelFormat.Opacity
- override fun getOpacity(): Int = PixelFormat.OPAQUE
- }
+ return PersonModel(key, name, drawable, clickIntent, sbn.user.identifier)
}
fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
@@ -272,4 +263,4 @@ private fun NotificationEntry.extractPersonKey(): PersonKey? =
if (isMessagingNotification()) key else null
private fun NotificationEntry.isMessagingNotification() =
- sbn.notification.notificationStyle == Notification.MessagingStyle::class.java \ No newline at end of file
+ sbn.notification.notificationStyle == Notification.MessagingStyle::class.java
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 3c247df692f4..a8a35d07b3f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -65,7 +65,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.Chronometer;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -150,7 +149,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private StatusBarStateController mStatusbarStateController;
private KeyguardBypassController mBypassController;
private LayoutListener mLayoutListener;
- private final NotificationContentInflater mNotificationInflater;
+ private NotificationRowContentBinder mNotificationContentBinder;
private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
private int mMaxHeadsUpHeightBeforeN;
@@ -464,7 +463,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* Inflate views based off the inflation flags set. Inflation happens asynchronously.
*/
public void inflateViews() {
- mNotificationInflater.bindContent(mEntry, this, mInflationFlags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, mInflationFlags, mBindParams,
false /* forceInflate */, mInflationCallback);
}
@@ -478,7 +477,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
// View should not be reinflated in the future
clearInflationFlags(inflationFlag);
Runnable freeViewRunnable =
- () -> mNotificationInflater.unbindContent(mEntry, this, inflationFlag);
+ () -> mNotificationContentBinder.unbindContent(mEntry, this, inflationFlag);
switch (inflationFlag) {
case FLAG_CONTENT_VIEW_HEADS_UP:
getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
@@ -742,23 +741,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mIsHeadsUp || mHeadsupDisappearRunning;
}
-
- public void setGroupManager(NotificationGroupManager groupManager) {
- mGroupManager = groupManager;
- mPrivateLayout.setGroupManager(groupManager);
- }
-
public void setRemoteInputController(RemoteInputController r) {
mPrivateLayout.setRemoteInputController(r);
}
- public void setAppName(String appName) {
- mAppName = appName;
- if (mMenuRow != null && mMenuRow.getMenuView() != null) {
- mMenuRow.setAppName(mAppName);
- }
- }
-
public void addChildNotification(ExpandableNotificationRow row) {
addChildNotification(row, -1);
}
@@ -852,7 +838,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mIsChildInGroup = isChildInGroup;
if (mIsLowPriority) {
int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
- mNotificationInflater.bindContent(mEntry, this, flags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, flags, mBindParams,
false /* forceInflate */, mInflationCallback);
}
}
@@ -1105,10 +1091,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mPrivateLayout.getContractedNotificationHeader();
}
- public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
- mOnExpandClickListener = onExpandClickListener;
- }
-
public void setLongPressListener(LongPressListener longPressListener) {
mLongPressListener = longPressListener;
}
@@ -1131,10 +1113,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
public HeadsUpManager getHeadsUpManager() {
return mHeadsUpManager;
}
@@ -1259,7 +1237,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
l.reInflateViews();
}
mEntry.getSbn().clearPackageContext();
- mNotificationInflater.bindContent(mEntry, this, mInflationFlags, mBindParams,
+ mNotificationContentBinder.bindContent(mEntry, this, mInflationFlags, mBindParams,
true /* forceInflate */, mInflationCallback);
}
@@ -1634,10 +1612,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mBindParams.usesIncreasedHeadsUpHeight = use;
}
- public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
- mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
- }
-
/**
* Set callback for notification content inflation
*
@@ -1652,7 +1626,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mNeedsRedaction = needsRedaction;
if (needsRedaction) {
setInflationFlags(FLAG_CONTENT_VIEW_PUBLIC);
- mNotificationInflater.bindContent(mEntry, this, FLAG_CONTENT_VIEW_PUBLIC,
+ mNotificationContentBinder.bindContent(mEntry, this, FLAG_CONTENT_VIEW_PUBLIC,
mBindParams, false /* forceInflate */, mInflationCallback);
} else {
clearInflationFlags(FLAG_CONTENT_VIEW_PUBLIC);
@@ -1661,18 +1635,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- @VisibleForTesting
- public NotificationContentInflater getNotificationInflater() {
- return mNotificationInflater;
- }
-
public interface ExpansionLogger {
void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
- mNotificationInflater = new NotificationContentInflater();
mMenuRow = new NotificationMenuRow(mContext);
mImageResolver = new NotificationInlineImageResolver(context,
new NotificationInlineImageCache());
@@ -1680,8 +1648,30 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
initDimens();
}
- public void setBypassController(KeyguardBypassController bypassController) {
+ /**
+ * Initialize row.
+ */
+ public void initialize(
+ String appName,
+ String notificationKey,
+ ExpansionLogger logger,
+ KeyguardBypassController bypassController,
+ NotificationGroupManager groupManager,
+ HeadsUpManager headsUpManager,
+ NotificationRowContentBinder rowContentBinder,
+ OnExpandClickListener onExpandClickListener) {
+ mAppName = appName;
+ if (mMenuRow != null && mMenuRow.getMenuView() != null) {
+ mMenuRow.setAppName(mAppName);
+ }
+ mLogger = logger;
+ mLoggingKey = notificationKey;
mBypassController = bypassController;
+ mGroupManager = groupManager;
+ mPrivateLayout.setGroupManager(groupManager);
+ mHeadsUpManager = headsUpManager;
+ mNotificationContentBinder = rowContentBinder;
+ mOnExpandClickListener = onExpandClickListener;
}
public void setStatusBarStateController(StatusBarStateController statusBarStateController) {
@@ -2920,11 +2910,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return 0;
}
- public void setExpansionLogger(ExpansionLogger logger, String key) {
- mLogger = logger;
- mLoggingKey = key;
- }
-
public void onExpandedByGesture(boolean userExpanded) {
int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER;
if (mGroupManager.isSummaryOfGroup(mEntry.getSbn())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java
new file mode 100644
index 000000000000..c11c60fcdd04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCache.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import android.widget.RemoteViews;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+
+/**
+ * Caches {@link RemoteViews} for a notification's content views.
+ */
+public interface NotifRemoteViewCache {
+
+ /**
+ * Whether the notification has the remote view cached
+ *
+ * @param entry notification
+ * @param flag inflation flag for content view
+ * @return true if the remote view is cached
+ */
+ boolean hasCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Get the remote view for the content flag specified.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ * @return the remote view if it is cached, null otherwise
+ */
+ @Nullable RemoteViews getCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Cache a remote view for a given content flag on a notification.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ * @param remoteView remote view to store
+ */
+ void putCachedView(
+ NotificationEntry entry,
+ @InflationFlag int flag,
+ RemoteViews remoteView);
+
+ /**
+ * Remove a cached remote view for a given content flag on a notification.
+ *
+ * @param entry notification
+ * @param flag inflation flag for the content view
+ */
+ void removeCachedView(NotificationEntry entry, @InflationFlag int flag);
+
+ /**
+ * Clear a notification's remote view cache.
+ *
+ * @param entry notification
+ */
+ void clearCache(NotificationEntry entry);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java
new file mode 100644
index 000000000000..a19099a6ea52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Implementation of remote view cache that keeps remote views cached for all active notifications.
+ */
+public class NotifRemoteViewCacheImpl implements NotifRemoteViewCache {
+ private final Map<NotificationEntry, SparseArray<RemoteViews>> mNotifCachedContentViews =
+ new ArrayMap<>();
+
+ @Inject
+ NotifRemoteViewCacheImpl(NotificationEntryManager entryManager) {
+ entryManager.addNotificationEntryListener(mEntryListener);
+ }
+
+ @Override
+ public boolean hasCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ return getCachedView(entry, flag) != null;
+ }
+
+ @Override
+ public @Nullable RemoteViews getCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ return getContentViews(entry).get(flag);
+ }
+
+ @Override
+ public void putCachedView(
+ NotificationEntry entry,
+ @InflationFlag int flag,
+ RemoteViews remoteView) {
+ getContentViews(entry).put(flag, remoteView);
+ }
+
+ @Override
+ public void removeCachedView(NotificationEntry entry, @InflationFlag int flag) {
+ getContentViews(entry).remove(flag);
+ }
+
+ @Override
+ public void clearCache(NotificationEntry entry) {
+ getContentViews(entry).clear();
+ }
+
+ private @NonNull SparseArray<RemoteViews> getContentViews(NotificationEntry entry) {
+ SparseArray<RemoteViews> contentViews = mNotifCachedContentViews.get(entry);
+ if (contentViews == null) {
+ throw new IllegalStateException(
+ String.format("Remote view cache was never created for notification %s",
+ entry.getKey()));
+ }
+ return contentViews;
+ }
+
+ private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationEntry entry) {
+ mNotifCachedContentViews.put(entry, new SparseArray<>());
+ }
+
+ @Override
+ public void onEntryRemoved(
+ NotificationEntry entry,
+ @Nullable NotificationVisibility visibility,
+ boolean removedByUser) {
+ mNotifCachedContentViews.remove(entry);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 172b72e9b0fc..e1a6747b5398 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
@@ -26,7 +27,6 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
@@ -35,6 +35,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
@@ -49,17 +50,30 @@ import com.android.systemui.util.Assert;
import java.util.HashMap;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* {@link NotificationContentInflater} binds content to a {@link ExpandableNotificationRow} by
* asynchronously building the content's {@link RemoteViews} and applying it to the row.
*/
+@Singleton
+@VisibleForTesting(visibility = PACKAGE)
public class NotificationContentInflater implements NotificationRowContentBinder {
public static final String TAG = "NotifContentInflater";
- private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private boolean mInflateSynchronously = false;
- private final ArrayMap<Integer, RemoteViews> mCachedContentViews = new ArrayMap<>();
+ private final NotificationRemoteInputManager mRemoteInputManager;
+ private final NotifRemoteViewCache mRemoteViewCache;
+
+ @Inject
+ public NotificationContentInflater(
+ NotifRemoteViewCache remoteViewCache,
+ NotificationRemoteInputManager remoteInputManager) {
+ mRemoteViewCache = remoteViewCache;
+ mRemoteInputManager = remoteInputManager;
+ }
@Override
public void bindContent(
@@ -76,27 +90,27 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return;
}
- StatusBarNotification sbn = row.getEntry().getSbn();
+ StatusBarNotification sbn = entry.getSbn();
// To check if the notification has inline image and preload inline image if necessary.
row.getImageResolver().preloadImages(sbn.getNotification());
if (forceInflate) {
- mCachedContentViews.clear();
+ mRemoteViewCache.clearCache(entry);
}
AsyncInflationTask task = new AsyncInflationTask(
- sbn,
mInflateSynchronously,
contentToBind,
- mCachedContentViews,
+ mRemoteViewCache,
+ entry,
row,
bindParams.isLowPriority,
bindParams.isChildInGroup,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
callback,
- mRemoteViewClickHandler);
+ mRemoteInputManager.getRemoteViewsOnClickHandler());
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
} else {
@@ -123,13 +137,15 @@ public class NotificationContentInflater implements NotificationRowContentBinder
result = inflateSmartReplyViews(result, reInflateFlags, entry,
row.getContext(), packageContext, row.getHeadsUpManager(),
row.getExistingSmartRepliesAndActions());
+
apply(
inflateSynchronously,
result,
reInflateFlags,
- mCachedContentViews,
+ mRemoteViewCache,
+ entry,
row,
- mRemoteViewClickHandler,
+ mRemoteInputManager.getRemoteViewsOnClickHandler(),
null);
return result;
}
@@ -149,7 +165,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
int curFlag = 1;
while (contentToUnbind != 0) {
if ((contentToUnbind & curFlag) != 0) {
- freeNotificationView(row, curFlag);
+ freeNotificationView(entry, row, curFlag);
}
contentToUnbind &= ~curFlag;
curFlag = curFlag << 1;
@@ -157,34 +173,25 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
/**
- * Set click handler for notification remote views
- *
- * @param remoteViewClickHandler click handler for remote views
- */
- public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
- mRemoteViewClickHandler = remoteViewClickHandler;
- }
-
- /**
* Frees the content view associated with the inflation flag. Will only succeed if the
* view is safe to remove.
*
* @param inflateFlag the flag corresponding to the content view which should be freed
*/
- private void freeNotificationView(ExpandableNotificationRow row,
+ private void freeNotificationView(NotificationEntry entry, ExpandableNotificationRow row,
@InflationFlag int inflateFlag) {
switch (inflateFlag) {
case FLAG_CONTENT_VIEW_HEADS_UP:
if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) {
row.getPrivateLayout().setHeadsUpChild(null);
- mCachedContentViews.remove(FLAG_CONTENT_VIEW_HEADS_UP);
+ mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP);
row.getPrivateLayout().setHeadsUpInflatedSmartReplies(null);
}
break;
case FLAG_CONTENT_VIEW_PUBLIC:
if (row.getPublicLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) {
row.getPublicLayout().setContractedChild(null);
- mCachedContentViews.remove(FLAG_CONTENT_VIEW_PUBLIC);
+ mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC);
}
break;
case FLAG_CONTENT_VIEW_CONTRACTED:
@@ -245,11 +252,12 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return result;
}
- public static CancellationSignal apply(
+ private static CancellationSignal apply(
boolean inflateSynchronously,
InflationProgress result,
@InflationFlag int reInflateFlags,
- ArrayMap<Integer, RemoteViews> cachedContentViews,
+ NotifRemoteViewCache remoteViewCache,
+ NotificationEntry entry,
ExpandableNotificationRow row,
RemoteViews.OnClickHandler remoteViewClickHandler,
@Nullable InflationCallback callback) {
@@ -261,7 +269,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if ((reInflateFlags & flag) != 0) {
boolean isNewView =
!canReapplyRemoteView(result.newContentView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -273,8 +281,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return result.newContentView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
- row, isNewView, remoteViewClickHandler, callback, privateLayout,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler, callback, privateLayout,
privateLayout.getContractedChild(), privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
@@ -285,7 +293,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if (result.newExpandedView != null) {
boolean isNewView =
!canReapplyRemoteView(result.newExpandedView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -297,8 +305,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return result.newExpandedView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
- cachedContentViews, row, isNewView, remoteViewClickHandler,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getExpandedChild(),
privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
@@ -311,7 +319,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if (result.newHeadsUpView != null) {
boolean isNewView =
!canReapplyRemoteView(result.newHeadsUpView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -323,8 +331,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return result.newHeadsUpView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag,
- cachedContentViews, row, isNewView, remoteViewClickHandler,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler,
callback, privateLayout, privateLayout.getHeadsUpChild(),
privateLayout.getVisibleWrapper(
VISIBLE_TYPE_HEADSUP), runningInflations,
@@ -336,7 +344,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if ((reInflateFlags & flag) != 0) {
boolean isNewView =
!canReapplyRemoteView(result.newPublicView,
- cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC));
+ remoteViewCache.getCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -348,15 +356,16 @@ public class NotificationContentInflater implements NotificationRowContentBinder
return result.newPublicView;
}
};
- applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, cachedContentViews,
- row, isNewView, remoteViewClickHandler, callback,
+ applyRemoteView(inflateSynchronously, result, reInflateFlags, flag, remoteViewCache,
+ entry, row, isNewView, remoteViewClickHandler, callback,
publicLayout, publicLayout.getContractedChild(),
publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
}
// Let's try to finish, maybe nobody is even inflating anything
- finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations, callback, row);
+ finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
+ row);
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
() -> runningInflations.values().forEach(CancellationSignal::cancel));
@@ -369,7 +378,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
final InflationProgress result,
final @InflationFlag int reInflateFlags,
@InflationFlag int inflationId,
- final ArrayMap<Integer, RemoteViews> cachedContentViews,
+ final NotifRemoteViewCache remoteViewCache,
+ final NotificationEntry entry,
final ExpandableNotificationRow row,
boolean isNewView,
RemoteViews.OnClickHandler remoteViewClickHandler,
@@ -397,7 +407,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
existingWrapper.onReinflated();
}
} catch (Exception e) {
- handleInflationError(runningInflations, e, row.getEntry().getSbn(), callback);
+ handleInflationError(runningInflations, e, row.getEntry(), callback);
// Add a running inflation to make sure we don't trigger callbacks.
// Safe to do because only happens in tests.
runningInflations.put(inflationId, new CancellationSignal());
@@ -422,8 +432,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
existingWrapper.onReinflated();
}
runningInflations.remove(inflationId);
- finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations,
- callback, row);
+ finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations,
+ callback, entry, row);
}
@Override
@@ -448,7 +458,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
onViewApplied(newView);
} catch (Exception anotherException) {
runningInflations.remove(inflationId);
- handleInflationError(runningInflations, e, row.getEntry().getSbn(),
+ handleInflationError(runningInflations, e, row.getEntry(),
callback);
}
}
@@ -474,7 +484,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private static void handleInflationError(
HashMap<Integer, CancellationSignal> runningInflations, Exception e,
- StatusBarNotification notification, @Nullable InflationCallback callback) {
+ NotificationEntry notification, @Nullable InflationCallback callback) {
Assert.isMainThread();
runningInflations.values().forEach(CancellationSignal::cancel);
if (callback != null) {
@@ -488,11 +498,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder
* @return true if the inflation was finished
*/
private static boolean finishIfDone(InflationProgress result,
- @InflationFlag int reInflateFlags, ArrayMap<Integer, RemoteViews> cachedContentViews,
+ @InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
HashMap<Integer, CancellationSignal> runningInflations,
- @Nullable InflationCallback endListener, ExpandableNotificationRow row) {
+ @Nullable InflationCallback endListener, NotificationEntry entry,
+ ExpandableNotificationRow row) {
Assert.isMainThread();
- NotificationEntry entry = row.getEntry();
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
if (runningInflations.isEmpty()) {
@@ -500,23 +510,27 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if (result.inflatedContentView != null) {
// New view case
privateLayout.setContractedChild(result.inflatedContentView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED) != null) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED,
+ result.newContentView);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED)) {
// Reinflation case. Only update if it's still cached (i.e. view has not been
// freed while inflating).
- cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED,
+ result.newContentView);
}
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
if (result.inflatedExpandedView != null) {
privateLayout.setExpandedChild(result.inflatedExpandedView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED,
+ result.newExpandedView);
} else if (result.newExpandedView == null) {
privateLayout.setExpandedChild(null);
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, null);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
+ remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED,
+ result.newExpandedView);
}
if (result.newExpandedView != null) {
privateLayout.setExpandedInflatedSmartReplies(
@@ -530,12 +544,14 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
if (result.inflatedHeadsUpView != null) {
privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP,
+ result.newHeadsUpView);
} else if (result.newHeadsUpView == null) {
privateLayout.setHeadsUpChild(null);
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, null);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
+ remoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_HEADS_UP,
+ result.newHeadsUpView);
}
if (result.newHeadsUpView != null) {
privateLayout.setHeadsUpInflatedSmartReplies(
@@ -548,16 +564,18 @@ public class NotificationContentInflater implements NotificationRowContentBinder
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
if (result.inflatedPublicView != null) {
publicLayout.setContractedChild(result.inflatedPublicView);
- cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
- } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC) != null) {
- cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC,
+ result.newPublicView);
+ } else if (remoteViewCache.hasCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC)) {
+ remoteViewCache.putCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC,
+ result.newPublicView);
}
}
entry.headsUpStatusBarText = result.headsUpStatusBarText;
entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
if (endListener != null) {
- endListener.onAsyncInflationFinished(row.getEntry(), reInflateFlags);
+ endListener.onAsyncInflationFinished(entry, reInflateFlags);
}
return true;
}
@@ -615,7 +633,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
implements InflationCallback, InflationTask {
- private final StatusBarNotification mSbn;
+ private final NotificationEntry mEntry;
private final Context mContext;
private final boolean mInflateSynchronously;
private final boolean mIsLowPriority;
@@ -624,17 +642,17 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private final InflationCallback mCallback;
private final boolean mUsesIncreasedHeadsUpHeight;
private @InflationFlag int mReInflateFlags;
- private final ArrayMap<Integer, RemoteViews> mCachedContentViews;
+ private final NotifRemoteViewCache mRemoteViewCache;
private ExpandableNotificationRow mRow;
private Exception mError;
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private CancellationSignal mCancellationSignal;
private AsyncInflationTask(
- StatusBarNotification notification,
boolean inflateSynchronously,
@InflationFlag int reInflateFlags,
- ArrayMap<Integer, RemoteViews> cachedContentViews,
+ NotifRemoteViewCache cache,
+ NotificationEntry entry,
ExpandableNotificationRow row,
boolean isLowPriority,
boolean isChildInGroup,
@@ -642,11 +660,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder
boolean usesIncreasedHeadsUpHeight,
InflationCallback callback,
RemoteViews.OnClickHandler remoteViewClickHandler) {
+ mEntry = entry;
mRow = row;
- mSbn = notification;
mInflateSynchronously = inflateSynchronously;
mReInflateFlags = reInflateFlags;
- mCachedContentViews = cachedContentViews;
+ mRemoteViewCache = cache;
mContext = mRow.getContext();
mIsLowPriority = isLowPriority;
mIsChildInGroup = isChildInGroup;
@@ -654,7 +672,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder
mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
mRemoteViewClickHandler = remoteViewClickHandler;
mCallback = callback;
- NotificationEntry entry = row.getEntry();
entry.setInflationTask(this);
}
@@ -667,12 +684,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder
@Override
protected InflationProgress doInBackground(Void... params) {
try {
+ final StatusBarNotification sbn = mEntry.getSbn();
final Notification.Builder recoveredBuilder
= Notification.Builder.recoverBuilder(mContext,
- mSbn.getNotification());
+ sbn.getNotification());
- Context packageContext = mSbn.getPackageContext(mContext);
- Notification notification = mSbn.getNotification();
+ Context packageContext = sbn.getPackageContext(mContext);
+ Notification notification = sbn.getNotification();
if (notification.isMediaNotification()) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
packageContext);
@@ -681,7 +699,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext);
- return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mRow.getEntry(),
+ return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mEntry,
mRow.getContext(), packageContext, mRow.getHeadsUpManager(),
mRow.getExistingSmartRepliesAndActions());
} catch (Exception e) {
@@ -694,20 +712,20 @@ public class NotificationContentInflater implements NotificationRowContentBinder
protected void onPostExecute(InflationProgress result) {
if (mError == null) {
mCancellationSignal = apply(mInflateSynchronously, result, mReInflateFlags,
- mCachedContentViews, mRow, mRemoteViewClickHandler, this);
+ mRemoteViewCache, mEntry, mRow, mRemoteViewClickHandler, this);
} else {
handleError(mError);
}
}
private void handleError(Exception e) {
- mRow.getEntry().onInflationTaskFinished();
- StatusBarNotification sbn = mRow.getEntry().getSbn();
+ mEntry.onInflationTaskFinished();
+ StatusBarNotification sbn = mEntry.getSbn();
final String ident = sbn.getPackageName() + "/0x"
+ Integer.toHexString(sbn.getId());
Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
if (mCallback != null) {
- mCallback.handleInflationException(sbn,
+ mCallback.handleInflationException(mRow.getEntry(),
new InflationException("Couldn't inflate contentViews" + e));
}
}
@@ -729,17 +747,17 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
@Override
- public void handleInflationException(StatusBarNotification notification, Exception e) {
+ public void handleInflationException(NotificationEntry entry, Exception e) {
handleError(e);
}
@Override
public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
- mRow.getEntry().onInflationTaskFinished();
+ mEntry.onInflationTaskFinished();
mRow.onNotificationUpdated();
if (mCallback != null) {
- mCallback.onAsyncInflationFinished(mRow.getEntry(), inflatedFlags);
+ mCallback.onAsyncInflationFinished(mEntry, inflatedFlags);
}
// Notify the resolver that the inflation task has finished,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index 2fe54c00bb06..9b95bff4921c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -138,10 +137,10 @@ public interface NotificationRowContentBinder {
/**
* Callback for when there is an inflation exception
*
- * @param notification notification which failed to inflate content
+ * @param entry notification which failed to inflate content
* @param e exception
*/
- void handleInflationException(StatusBarNotification notification, Exception e);
+ void handleInflationException(NotificationEntry entry, Exception e);
/**
* Callback for after the content views finish inflating.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
new file mode 100644
index 000000000000..df8653cf2406
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import javax.inject.Singleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Dagger Module containing notification row and view inflation implementations.
+ */
+@Module
+public abstract class NotificationRowModule {
+ /**
+ * Provides notification row content binder instance.
+ */
+ @Binds
+ @Singleton
+ public abstract NotificationRowContentBinder provideNotificationRowContentBinder(
+ NotificationContentInflater contentBinderImpl);
+
+ /**
+ * Provides notification remote view cache instance.
+ */
+ @Binds
+ @Singleton
+ public abstract NotifRemoteViewCache provideNotifRemoteViewCache(
+ NotifRemoteViewCacheImpl cacheImpl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 2761689ec409..09c1fad423d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -187,18 +187,18 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
@Override
public boolean beginsSection(@NonNull View view, @Nullable View previous) {
boolean begin = false;
- if (view instanceof ExpandableNotificationRow) {
- if (previous instanceof ExpandableNotificationRow) {
+ if (view instanceof ActivatableNotificationView) {
+ if (previous instanceof ActivatableNotificationView) {
// If we're drawing the first non-person notification, break out a section
- ExpandableNotificationRow curr = (ExpandableNotificationRow) view;
- ExpandableNotificationRow prev = (ExpandableNotificationRow) previous;
+ ActivatableNotificationView curr = (ActivatableNotificationView) view;
+ ActivatableNotificationView prev = (ActivatableNotificationView) previous;
- begin = curr.getEntry().getBucket() != prev.getEntry().getBucket();
+ begin = getBucket(curr) != getBucket(prev);
}
}
if (!begin) {
- begin = view == mGentleHeader || previous == mPeopleHubView;
+ begin = view == mGentleHeader || view == mPeopleHubView;
}
return begin;
@@ -230,29 +230,42 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
return;
}
- int lastPersonIndex = -1;
- int firstGentleNotifIndex = -1;
+ boolean peopleNotificationsPresent = false;
+ int firstNonHeadsUpIndex = -1;
+ int firstGentleIndex = -1;
+ int notifCount = 0;
final int n = mParent.getChildCount();
for (int i = 0; i < n; i++) {
View child = mParent.getChildAt(i);
- if (child instanceof ExpandableNotificationRow
- && child.getVisibility() != View.GONE) {
+ if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
+ notifCount++;
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) {
+ firstNonHeadsUpIndex = i;
+ }
if (row.getEntry().getBucket() == BUCKET_PEOPLE) {
- lastPersonIndex = i;
+ peopleNotificationsPresent = true;
}
if (row.getEntry().getBucket() == BUCKET_SILENT) {
- firstGentleNotifIndex = i;
+ firstGentleIndex = i;
break;
}
}
}
+ if (firstNonHeadsUpIndex == -1) {
+ firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount;
+ }
+
// make room for peopleHub
- firstGentleNotifIndex += adjustPeopleHubVisibilityAndPosition(lastPersonIndex);
+ int offset = adjustPeopleHubVisibilityAndPosition(
+ firstNonHeadsUpIndex, peopleNotificationsPresent);
+ if (firstGentleIndex != -1) {
+ firstGentleIndex += offset;
+ }
- adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex);
+ adjustGentleHeaderVisibilityAndPosition(firstGentleIndex);
mGentleHeader.setAreThereDismissableGentleNotifs(
mParent.hasActiveClearableNotifications(ROWS_GENTLE));
@@ -294,13 +307,15 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
}
}
- private int adjustPeopleHubVisibilityAndPosition(int lastPersonIndex) {
- final boolean showPeopleHeader = mPeopleHubVisible
- && mNumberOfSections > 2
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
+ private int adjustPeopleHubVisibilityAndPosition(
+ int targetIndex, boolean peopleNotificationsPresent) {
+ final boolean showPeopleHeader = mNumberOfSections > 2
+ && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+ && (peopleNotificationsPresent || mPeopleHubVisible);
final int currentHubIndex = mParent.indexOfChild(mPeopleHubView);
final boolean currentlyVisible = currentHubIndex >= 0;
- int targetIndex = lastPersonIndex + 1;
+
+ mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent);
if (!showPeopleHeader) {
if (currentlyVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 6d0fcc386281..4845ea16020b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -31,6 +31,7 @@ import com.android.systemui.SwipeHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper {
@@ -298,8 +299,8 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
@Override
public Animator getViewTranslationAnimator(View v, float target,
ValueAnimator.AnimatorUpdateListener listener) {
- if (v instanceof SwipeableView) {
- return ((SwipeableView) v).getTranslateViewAnimator(target, listener);
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
} else {
return superGetViewTranslationAnimator(v, target, listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index a0796060e9d8..e5717aeefdcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -16,38 +16,22 @@
package com.android.systemui.statusbar.notification.stack
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
-import android.util.FloatProperty
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
import com.android.systemui.statusbar.notification.people.DataListener
import com.android.systemui.statusbar.notification.people.PersonViewModel
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") {
- override fun setValue(view: PeopleHubView, value: Float) {
- view.translation = value
- }
-
- override fun get(view: PeopleHubView) = view.translation
-}
-
class PeopleHubView(context: Context, attrs: AttributeSet) :
ActivatableNotificationView(context, attrs), SwipeableView {
private lateinit var contents: ViewGroup
private lateinit var personControllers: List<PersonDataListenerImpl>
- private var translateAnim: ObjectAnimator? = null
val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
get() = personControllers.asSequence()
@@ -56,9 +40,10 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
super.onFinishInflate()
contents = requireViewById(R.id.people_list)
personControllers = (0 until contents.childCount)
+ .reversed()
.asSequence()
.mapNotNull { idx ->
- (contents.getChildAt(idx) as? LinearLayout)?.let(::PersonDataListenerImpl)
+ (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
}
.toList()
}
@@ -69,41 +54,32 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
override fun createMenu(): NotificationMenuRowPlugin? = null
- override fun getTranslateViewAnimator(
- leftTarget: Float,
- listener: ValueAnimator.AnimatorUpdateListener?
- ): Animator =
- ObjectAnimator
- .ofFloat(this, TRANSLATE_CONTENT, leftTarget)
- .apply {
- listener?.let { addUpdateListener(listener) }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(anim: Animator) {
- translateAnim = null
- }
- })
- }
- .also {
- translateAnim?.cancel()
- translateAnim = it
- }
-
override fun resetTranslation() {
- translateAnim?.cancel()
translationX = 0f
}
- private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) :
- DataListener<PersonViewModel?> {
+ override fun setTranslation(translation: Float) {
+ if (canSwipe) {
+ super.setTranslation(translation)
+ }
+ }
- val nameView = viewGroup.requireViewById<TextView>(R.id.person_name)
- val avatarView = viewGroup.requireViewById<ImageView>(R.id.person_icon)
+ var canSwipe: Boolean = true
+ set(value) {
+ if (field != value) {
+ if (field) {
+ resetTranslation()
+ }
+ field = value
+ }
+ }
+
+ private inner class PersonDataListenerImpl(val avatarView: ImageView) :
+ DataListener<PersonViewModel?> {
override fun onDataChanged(data: PersonViewModel?) {
- viewGroup.visibility = data?.let { View.VISIBLE } ?: View.INVISIBLE
- nameView.text = data?.name
avatarView.setImageDrawable(data?.icon)
- viewGroup.setOnClickListener { data?.onClick?.invoke() }
+ avatarView.setOnClickListener { data?.onClick?.invoke() }
}
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
index 6c6ef61cfdaf..49e59a2e7200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-
import androidx.annotation.Nullable;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -32,10 +29,6 @@ public interface SwipeableView {
/** Optionally creates a menu for this view. */
@Nullable NotificationMenuRowPlugin createMenu();
- /** Animator for translating the view, simulating a swipe. */
- Animator getTranslateViewAnimator(
- float leftTarget, ValueAnimator.AnimatorUpdateListener listener);
-
/** Sets the translation amount for an in-progress swipe. */
void setTranslation(float translate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index f7d52b5f5ab0..ad1aa8370495 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -98,7 +98,12 @@ class KeyguardBypassController : Dumpable {
bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
}
}, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
- lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
+ lockscreenUserManager.addUserChangedListener(
+ object : NotificationLockscreenUserManager.UserChangedListener {
+ override fun onUserChanged(userId: Int) {
+ pendingUnlockType = null
+ }
+ })
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index fe0739f9088c..896b6e570da2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -32,7 +32,6 @@ import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
@@ -428,7 +427,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
* The notification is still pending inflation but we've decided that we no longer need
* the content view (e.g. suppression might have changed and we decided we need to transfer
* back). However, there is no way to abort just this inflation if other inflation requests
- * have started (see {@link AsyncInflationTask#supersedeTask(InflationTask)}). So instead
+ * have started (see {@link InflationTask#supersedeTask(InflationTask)}). So instead
* we just flag it as aborted and free when it's inflated.
*/
boolean mAbortOnInflation;
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 9dc8fbf900b6..0f3af095f7be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,8 +24,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
-import com.android.internal.annotations.VisibleForTesting;
-
public class NotificationPanelView extends PanelView {
private static final boolean DEBUG = false;
@@ -38,14 +36,10 @@ public class NotificationPanelView extends PanelView {
static final String COUNTER_PANEL_OPEN = "panel_open";
static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
- @VisibleForTesting
- protected KeyguardAffordanceHelper mAffordanceHelper;
-
- private int mOldLayoutDirection;
-
private int mCurrentPanelAlpha;
private final Paint mAlphaPaint = new Paint();
private boolean mDozing;
+ private RtlChangeListener mRtlChangeListener;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -57,9 +51,8 @@ public class NotificationPanelView extends PanelView {
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
- if (layoutDirection != mOldLayoutDirection) {
- mAffordanceHelper.onRtlPropertiesChanged();
- mOldLayoutDirection = layoutDirection;
+ if (mRtlChangeListener != null) {
+ mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
}
}
@@ -95,4 +88,11 @@ public class NotificationPanelView extends PanelView {
return !mDozing;
}
+ void setRtlChangeListener(RtlChangeListener listener) {
+ mRtlChangeListener = listener;
+ }
+
+ interface RtlChangeListener {
+ void onRtlPropertielsChanged(int layoutDirection);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index bbde25bb482e..90ec2a076e87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -449,6 +449,7 @@ public class NotificationPanelViewController extends PanelViewController {
private PluginManager mPluginManager;
private FrameLayout mPluginFrame;
private NPVPluginManager mNPVPluginManager;
+ private int mOldLayoutDirection;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -603,6 +604,13 @@ public class NotificationPanelViewController extends PanelViewController {
}
}, HomeControlsPlugin.class, false);
+
+ mView.setRtlChangeListener(layoutDirection -> {
+ if (layoutDirection != mOldLayoutDirection) {
+ mAffordanceHelper.onRtlPropertiesChanged();
+ mOldLayoutDirection = layoutDirection;
+ }
+ });
}
@Override
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 277a7613aafb..30825ed65eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -205,6 +205,7 @@ import com.android.systemui.statusbar.notification.collection.init.NewNotifPipel
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -413,6 +414,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
private final NotificationEntryManager mEntryManager;
+ private final NotificationRowContentBinder mRowContentBinder;
private NotificationListController mNotificationListController;
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
@@ -634,6 +636,7 @@ public class StatusBar extends SystemUI implements DemoMode,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -715,6 +718,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mEntryManager = notificationEntryManager;
+ mRowContentBinder = notificationRowContentBinder;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
@@ -1240,6 +1244,7 @@ public class StatusBar extends SystemUI implements DemoMode,
final NotificationRowBinderImpl rowBinder =
new NotificationRowBinderImpl(
mContext,
+ mRowContentBinder,
mAllowNotificationLongPress,
mKeyguardBypassController,
mStatusBarStateController,
@@ -1272,7 +1277,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- mEntryManager.setRowBinder(rowBinder);
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mEntryManager.setRowBinder(rowBinder);
+ rowBinder.setInflationCallback(mEntryManager);
+ }
+
mRemoteInputUriController.attach(mEntryManager);
rowBinder.setNotificationClicker(new NotificationClicker(
@@ -1282,7 +1291,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationListController.bind();
if (mFeatureFlags.isNewNotifPipelineEnabled()) {
- mNewNotifPipeline.get().initialize(mNotificationListener);
+ mNewNotifPipeline.get().initialize(mNotificationListener, rowBinder);
}
mEntryManager.attach(mNotificationListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 153ca22933a9..df741079de29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -125,6 +126,7 @@ public class StatusBarModule {
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationEntryManager notificationEntryManager,
+ NotificationRowContentBinder notificationRowContentBinder,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -207,6 +209,7 @@ public class StatusBarModule {
notificationGutsManager,
notificationLogger,
notificationEntryManager,
+ notificationRowContentBinder,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
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 0fd0dabbc3f2..12a65169e1df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -217,7 +217,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
notificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
- mEntryManager, this);
+ this);
mNotificationInterruptionStateProvider.setUpWithPresenter(
this, mHeadsUpManager, this::canHeadsUp);
mLockscreenUserManager.setUpWithPresenter(this);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
new file mode 100644
index 000000000000..d413308d4573
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -0,0 +1,333 @@
+/*
+ * 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowInsets;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
+ */
+@Singleton
+public class DisplayImeController implements DisplayWindowController.DisplayWindowListener {
+ private static final String TAG = "DisplayImeController";
+
+ static final int ANIMATION_DURATION_SHOW_MS = 275;
+ static final int ANIMATION_DURATION_HIDE_MS = 340;
+ static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ private static final int DIRECTION_NONE = 0;
+ private static final int DIRECTION_SHOW = 1;
+ private static final int DIRECTION_HIDE = 2;
+
+ SystemWindows mSystemWindows;
+ final Handler mHandler;
+
+ final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
+
+ final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
+
+ @Inject
+ DisplayImeController(SystemWindows syswin, DisplayWindowController displayController,
+ @Main Handler mainHandler) {
+ mHandler = mainHandler;
+ mSystemWindows = syswin;
+ displayController.addDisplayWindowListener(this);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // Add's a system-ui window-manager specifically for ime. This type is special because
+ // WM will defer IME inset handling to it in multi-window scenarious.
+ PerDisplay pd = new PerDisplay(displayId,
+ mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation());
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to set insets controller on display " + displayId);
+ }
+ mImePerDisplay.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return;
+ }
+ if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
+ != pd.mRotation && isImeShowing(displayId)) {
+ pd.startAnimation(true);
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+ }
+ mImePerDisplay.remove(displayId);
+ }
+
+ private boolean isImeShowing(int displayId) {
+ PerDisplay pd = mImePerDisplay.get(displayId);
+ if (pd == null) {
+ return false;
+ }
+ final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME);
+ return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible();
+ }
+
+ private void dispatchPositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImePositionChanged(displayId, imeTop, t);
+ }
+ }
+ }
+
+ private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop,
+ boolean show, SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t);
+ }
+ }
+ }
+
+ private void dispatchEndPositioning(int displayId, int imeTop, boolean show,
+ SurfaceControl.Transaction t) {
+ synchronized (mPositionProcessors) {
+ for (ImePositionProcessor pp : mPositionProcessors) {
+ pp.onImeEndPositioning(displayId, imeTop, show, t);
+ }
+ }
+ }
+
+ /**
+ * Adds an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void addPositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ if (mPositionProcessors.contains(processor)) {
+ return;
+ }
+ mPositionProcessors.add(processor);
+ }
+ }
+
+ /**
+ * Removes an {@link ImePositionProcessor} to be called during ime position updates.
+ */
+ public void removePositionProcessor(ImePositionProcessor processor) {
+ synchronized (mPositionProcessors) {
+ mPositionProcessors.remove(processor);
+ }
+ }
+
+ class PerDisplay extends IDisplayWindowInsetsController.Stub {
+ final int mDisplayId;
+ final InsetsState mInsetsState = new InsetsState();
+ InsetsSourceControl mImeSourceControl = null;
+ int mAnimationDirection = DIRECTION_NONE;
+ ValueAnimator mAnimation = null;
+ int mRotation = Surface.ROTATION_0;
+
+ PerDisplay(int displayId, int initialRotation) {
+ mDisplayId = displayId;
+ mRotation = initialRotation;
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+ mInsetsState.set(insetsState, true /* copySources */);
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ insetsChanged(insetsState);
+ if (activeControls != null) {
+ for (InsetsSourceControl activeControl : activeControls) {
+ if (activeControl == null) {
+ continue;
+ }
+ if (activeControl.getType() == InsetsState.ITYPE_IME) {
+ mImeSourceControl = activeControl;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void showInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(true /* show */);
+ }
+
+ @Override
+ public void hideInsets(int types, boolean fromIme) {
+ if ((types & WindowInsets.Type.ime()) == 0) {
+ return;
+ }
+ startAnimation(false /* show */);
+ }
+
+ /**
+ * Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
+ */
+ private void setVisibleDirectly(boolean visible) {
+ mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible);
+ try {
+ mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private int imeTop(InsetsSource imeSource, float surfaceOffset) {
+ return imeSource.getFrame().top + (int) surfaceOffset;
+ }
+
+ private void startAnimation(final boolean show) {
+ final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
+ if (imeSource == null || mImeSourceControl == null) {
+ return;
+ }
+ if ((mAnimationDirection == DIRECTION_SHOW && show)
+ || (mAnimationDirection == DIRECTION_HIDE && !show)) {
+ return;
+ }
+ if (mAnimationDirection != DIRECTION_NONE) {
+ mAnimation.end();
+ mAnimationDirection = DIRECTION_NONE;
+ }
+ mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
+ mHandler.post(() -> {
+ final float defaultY = mImeSourceControl.getSurfacePosition().y;
+ final float x = mImeSourceControl.getSurfacePosition().x;
+ final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY;
+ final float endY = show ? defaultY : defaultY + imeSource.getFrame().height();
+ mAnimation = ValueAnimator.ofFloat(startY, endY);
+ mAnimation.setDuration(
+ show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS);
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ float value = (float) animation.getAnimatedValue();
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
+ dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t);
+ t.apply();
+ t.close();
+ });
+ mAnimation.setInterpolator(INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY),
+ imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW,
+ t);
+ if (mAnimationDirection == DIRECTION_SHOW) {
+ t.show(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setPosition(mImeSourceControl.getLeash(), x, endY);
+ dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY),
+ mAnimationDirection == DIRECTION_SHOW, t);
+ if (mAnimationDirection == DIRECTION_HIDE) {
+ t.hide(mImeSourceControl.getLeash());
+ }
+ t.apply();
+ t.close();
+
+ mAnimationDirection = DIRECTION_NONE;
+ mAnimation = null;
+ }
+ });
+ if (!show) {
+ // When going away, queue up insets change first, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(false /* visible */);
+ }
+ mAnimation.start();
+ if (show) {
+ // When showing away, queue up insets change last, otherwise any bounds changes
+ // can have a "flicker" of ime-provided insets.
+ setVisibleDirectly(true /* visible */);
+ }
+ });
+ }
+ }
+
+ /**
+ * Allows other things to synchronize with the ime position
+ */
+ public interface ImePositionProcessor {
+ /**
+ * Called when the IME position is starting to animate.
+ */
+ void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing,
+ SurfaceControl.Transaction t);
+
+ /**
+ * Called when the ime position changed. This is expected to be a synchronous call on the
+ * animation thread. Operations can be added to the transaction to be applied in sync.
+ */
+ void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t);
+
+ /**
+ * Called when the IME position is done animating.
+ */
+ void onImeEndPositioning(int displayId, int imeTop, boolean showing,
+ SurfaceControl.Transaction t);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index b70fdbd4a2d8..eccf09633f16 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -19,7 +19,7 @@ package com.android.keyguard;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
@@ -83,14 +83,14 @@ public class CarrierTextControllerTest extends SysuiTestCase {
private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
private static final int TEST_CARRIER_ID = 1;
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_NULL = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, null, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
+ TEST_CARRIER, null, NAME_SOURCE_DEFAULT, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
null, null, null, null, false, null, "");
private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
@Mock
private WifiManager mWifiManager;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 40ea6ddbbe38..0c22aaeaafb9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,7 @@
package com.android.keyguard;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static com.google.common.truth.Truth.assertThat;
@@ -84,11 +84,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private static final int TEST_CARRIER_ID = 1;
private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
- TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
@Mock
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 40b0ba9bf633..3fdbd3edfcaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -47,6 +47,9 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpansionLogger;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewCache;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -72,6 +75,7 @@ public class NotificationTestHelper {
public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
private static final String GROUP_KEY = "gruKey";
+ private static final String APP_NAME = "appName";
private final Context mContext;
private int mId;
@@ -303,9 +307,6 @@ public class NotificationTestHelper {
null /* root */,
false /* attachToRoot */);
ExpandableNotificationRow row = mRow;
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setAboveShelfChangedListener(aboveShelf -> {});
final NotificationChannel channel =
new NotificationChannel(
@@ -329,6 +330,23 @@ public class NotificationTestHelper {
entry.setRow(row);
entry.createIcons(mContext, entry.getSbn());
row.setEntry(entry);
+
+ NotificationContentInflater contentBinder = new NotificationContentInflater(
+ mock(NotifRemoteViewCache.class),
+ mock(NotificationRemoteInputManager.class));
+ contentBinder.setInflateSynchronously(true);
+
+ row.initialize(
+ APP_NAME,
+ entry.getKey(),
+ mock(ExpansionLogger.class),
+ mock(KeyguardBypassController.class),
+ mGroupManager,
+ mHeadsUpManager,
+ contentBinder,
+ mock(OnExpandClickListener.class));
+ row.setAboveShelfChangedListener(aboveShelf -> { });
+
row.setInflationFlags(extraInflationFlags);
inflateAndWait(row);
@@ -341,11 +359,10 @@ public class NotificationTestHelper {
private static void inflateAndWait(ExpandableNotificationRow row) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(1);
- row.getNotificationInflater().setInflateSynchronously(true);
NotificationContentInflater.InflationCallback callback =
new NotificationContentInflater.InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
countDownLatch.countDown();
}
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 f55ea4ff8ef2..1c294531ea68 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
@@ -65,6 +65,7 @@ import com.android.systemui.ForegroundServiceController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -86,7 +87,10 @@ import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewCache;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -143,6 +147,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private RowInflaterTask mAsyncInflationTask;
@Mock private NotificationRowBinder mMockedRowBinder;
@Mock private NotifLog mNotifLog;
+ @Mock private FeatureFlags mFeatureFlags;
private int mId;
private NotificationEntry mEntry;
@@ -219,6 +224,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry.expandedIcon = mock(StatusBarIconView.class);
+ when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
+ when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mEntryManager = new TestableNotificationEntryManager(
mNotifLog,
mGroupManager,
@@ -230,19 +237,27 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mNotifLog,
mock(NotificationSectionsFeatureManager.class),
mock(PeopleNotificationIdentifier.class)),
- mEnvironment
+ mEnvironment,
+ mFeatureFlags
);
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
+ NotificationRowContentBinder contentBinder = new NotificationContentInflater(
+ mock(NotifRemoteViewCache.class),
+ mRemoteInputManager);
+
NotificationRowBinderImpl notificationRowBinder =
- new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
+ new NotificationRowBinderImpl(mContext,
+ contentBinder,
+ true, /* allowLongPress */
mock(KeyguardBypassController.class),
mock(StatusBarStateController.class),
mock(NotificationLogger.class));
notificationRowBinder.setUpWithPresenter(
- mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
+ mPresenter, mListContainer, mHeadsUpManager, mBindCallback);
+ notificationRowBinder.setInflationCallback(mEntryManager);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
mEntryManager.setRowBinder(notificationRowBinder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index 34beefe9843b..1afee120e495 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification
+import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
@@ -33,8 +34,9 @@ class TestableNotificationEntryManager(
log: NotifLog,
gm: NotificationGroupManager,
rm: NotificationRankingManager,
- ke: KeyguardEnvironment
-) : NotificationEntryManager(log, gm, rm, ke) {
+ ke: KeyguardEnvironment,
+ ff: FeatureFlags
+) : NotificationEntryManager(log, gm, rm, ke, ff) {
public var countDownLatch: CountDownLatch = CountDownLatch(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 0837a42ae700..28feacac8c44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.collection.NotifCollec
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -261,9 +262,13 @@ public class NotifCollectionTest extends SysuiTestCase {
.setRank(5)
.setExplanation("baz buzz")
.build();
+
+ // WHEN entry3's ranking update includes an update to its overrideGroupKey
+ final String newOverrideGroupKey = "newOverrideGroupKey";
Ranking newRanking3 = new RankingBuilder(notif3.ranking)
.setRank(6)
.setExplanation("Penguin pizza")
+ .setOverrideGroupKey(newOverrideGroupKey)
.build();
mNoMan.setRanking(notif1.sbn.getKey(), newRanking1);
@@ -275,6 +280,10 @@ public class NotifCollectionTest extends SysuiTestCase {
assertEquals(newRanking1, entry1.getRanking());
assertEquals(newRanking2, entry2.getRanking());
assertEquals(newRanking3, entry3.getRanking());
+
+ // THEN the entry3's overrideGroupKey is updated along with its groupKey
+ assertEquals(newOverrideGroupKey, entry3.getSbn().getOverrideGroupKey());
+ assertNotNull(entry3.getSbn().getGroupKey());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 0764d0cd4b88..867a9b97d622 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -178,9 +178,10 @@ private fun <T> castNull(): T = null as T
private fun fakePersonModel(
id: String,
name: CharSequence,
- clickIntent: PendingIntent
+ clickIntent: PendingIntent,
+ userId: Int = 0
): PersonModel =
- PersonModel(id, name, mock(Drawable::class.java), clickIntent)
+ PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId)
private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
@@ -207,4 +208,4 @@ class FakeDataListener<T> : DataListener<T> {
override fun onDataChanged(data: T) {
lastSeen = Maybe.Just(data)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
new file mode 100644
index 000000000000..d7214f3b9228
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.widget.RemoteViews;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class NotifRemoteViewCacheImplTest extends SysuiTestCase {
+
+ private NotifRemoteViewCacheImpl mNotifRemoteViewCache;
+ private NotificationEntry mEntry;
+ private NotificationEntryListener mEntryListener;
+ @Mock private RemoteViews mRemoteViews;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mEntry = new NotificationEntryBuilder().build();
+
+ NotificationEntryManager entryManager = mock(NotificationEntryManager.class);
+ mNotifRemoteViewCache = new NotifRemoteViewCacheImpl(entryManager);
+ ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
+ ArgumentCaptor.forClass(NotificationEntryListener.class);
+ verify(entryManager).addNotificationEntryListener(entryListenerCaptor.capture());
+ mEntryListener = entryListenerCaptor.getValue();
+ }
+
+ @Test
+ public void testPutCachedView() {
+ // GIVEN an initialized cache for an entry.
+ mEntryListener.onPendingEntryAdded(mEntry);
+
+ // WHEN a notification's cached remote views is put in.
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+
+ // THEN the remote view is cached.
+ assertTrue(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ assertEquals(
+ "Cached remote view is not the one we put in.",
+ mRemoteViews,
+ mNotifRemoteViewCache.getCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ }
+
+ @Test
+ public void testRemoveCachedView() {
+ // GIVEN a cache with a cached view.
+ mEntryListener.onPendingEntryAdded(mEntry);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+
+ // WHEN we remove the cached view.
+ mNotifRemoteViewCache.removeCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED);
+
+ // THEN the remote view is not cached.
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ }
+
+ @Test
+ public void testClearCache() {
+ // GIVEN a non-empty cache.
+ mEntryListener.onPendingEntryAdded(mEntry);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED, mRemoteViews);
+ mNotifRemoteViewCache.putCachedView(mEntry, FLAG_CONTENT_VIEW_EXPANDED, mRemoteViews);
+
+ // WHEN we clear the cache.
+ mNotifRemoteViewCache.clearCache(mEntry);
+
+ // THEN the cache is empty.
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_CONTRACTED));
+ assertFalse(mNotifRemoteViewCache.hasCachedView(mEntry, FLAG_CONTENT_VIEW_EXPANDED));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index dc4e4980e443..cb9da6a40cb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -22,30 +22,35 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams;
@@ -58,6 +63,8 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
@@ -74,8 +81,11 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
private Notification.Builder mBuilder;
private ExpandableNotificationRow mRow;
+ @Mock private NotifRemoteViewCache mCache;
+
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mBuilder = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
.setContentTitle("Title")
@@ -84,7 +94,9 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
ExpandableNotificationRow row = new NotificationTestHelper(mContext, mDependency).createRow(
mBuilder.build());
mRow = spy(row);
- mNotificationInflater = new NotificationContentInflater();
+ mNotificationInflater = new NotificationContentInflater(
+ mCache,
+ mock(NotificationRemoteInputManager.class));
}
@Test
@@ -175,11 +187,13 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
result,
FLAG_CONTENT_VIEW_EXPANDED,
0,
- new ArrayMap() /* cachedContentViews */, mRow,
+ mock(NotifRemoteViewCache.class),
+ mRow.getEntry(),
+ mRow,
true /* isNewView */, (v, p, r) -> true,
new InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
countDownLatch.countDown();
throw new RuntimeException("No Exception expected");
@@ -245,6 +259,71 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
NotificationContentInflater.canReapplyRemoteView(mediaView, decoratedMediaView));
}
+ @Test
+ public void testUsesSameViewWhenCachedPossibleToReuse() throws Exception {
+ // GIVEN a cached view.
+ RemoteViews contractedRemoteView = mBuilder.createContentView();
+ when(mCache.hasCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(true);
+ when(mCache.getCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(contractedRemoteView);
+
+ // GIVEN existing bound view with same layout id.
+ View view = contractedRemoteView.apply(mContext, null /* parent */);
+ mRow.getPrivateLayout().setContractedChild(view);
+
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN the view should be re-used
+ assertEquals("Binder inflated a new view even though the old one was cached and usable.",
+ view, mRow.getPrivateLayout().getContractedChild());
+ }
+
+ @Test
+ public void testInflatesNewViewWhenCachedNotPossibleToReuse() throws Exception {
+ // GIVEN a cached remote view.
+ RemoteViews contractedRemoteView = mBuilder.createHeadsUpContentView();
+ when(mCache.hasCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(true);
+ when(mCache.getCachedView(mRow.getEntry(), FLAG_CONTENT_VIEW_CONTRACTED))
+ .thenReturn(contractedRemoteView);
+
+ // GIVEN existing bound view with different layout id.
+ View view = new TextView(mContext);
+ mRow.getPrivateLayout().setContractedChild(view);
+
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN the view should be a new view
+ assertNotEquals("Binder (somehow) used the same view when inflating.",
+ view, mRow.getPrivateLayout().getContractedChild());
+ }
+
+ @Test
+ public void testInflationCachesCreatedRemoteView() throws Exception {
+ // WHEN inflater inflates
+ inflateAndWait(mNotificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, mRow);
+
+ // THEN inflater informs cache of the new remote view
+ verify(mCache).putCachedView(
+ eq(mRow.getEntry()),
+ eq(FLAG_CONTENT_VIEW_CONTRACTED),
+ any());
+ }
+
+ @Test
+ public void testUnbindRemovesCachedRemoteView() {
+ // WHEN inflated unbinds content
+ mNotificationInflater.unbindContent(mRow.getEntry(), mRow, FLAG_CONTENT_VIEW_HEADS_UP);
+
+ // THEN inflated informs cache to remove remote view
+ verify(mCache).removeCachedView(
+ eq(mRow.getEntry()),
+ eq(FLAG_CONTENT_VIEW_HEADS_UP));
+ }
+
private static void inflateAndWait(NotificationContentInflater inflater,
@InflationFlag int contentToInflate,
ExpandableNotificationRow row)
@@ -261,7 +340,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
inflater.setInflateSynchronously(true);
InflationCallback callback = new InflationCallback() {
@Override
- public void handleInflationException(StatusBarNotification notification,
+ public void handleInflationException(NotificationEntry entry,
Exception e) {
if (!expectingException) {
exceptionHolder.setException(e);
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 77a6a2602d8e..39f037cfa70d 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
@@ -53,6 +53,7 @@ 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.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -166,7 +167,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(NotificationSectionsFeatureManager.class),
mock(PeopleNotificationIdentifier.class)
),
- mock(NotificationEntryManager.KeyguardEnvironment.class));
+ mock(NotificationEntryManager.KeyguardEnvironment.class),
+ mock(FeatureFlags.class));
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
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 7e485f45e5e6..3da87ea2fb56 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
@@ -122,6 +122,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -247,6 +248,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private NotificationEntryManager mEntryManager;
+ @Mock private NotificationContentInflater mNotificationContentInflater;
@Mock private LockscreenLockIconController mLockscreenLockIconController;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
@@ -356,6 +358,7 @@ public class StatusBarTest extends SysuiTestCase {
mNotificationGutsManager,
notificationLogger,
mEntryManager,
+ mNotificationContentInflater,
mNotificationInterruptionStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 0be853a81fb2..797b713d8614 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -20,7 +20,7 @@ java_defaults {
srcs: [
"src/**/*.java",
":framework-tethering-shared-srcs",
- ":net-module-utils-srcs",
+ ":tethering-module-utils-srcs",
":services-tethering-shared-srcs",
],
static_libs: [
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index a49ab85d2faf..11e57186c666 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,8 +15,6 @@
*/
package android.net;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-
import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager.OnTetheringEventCallback;
@@ -52,6 +50,103 @@ public class TetheringManager {
private TetheringConfigurationParcel mTetheringConfiguration;
private TetherStatesParcel mTetherStatesParcel;
+ /**
+ * Broadcast Action: A tetherable connection has come or gone.
+ * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER},
+ * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY},
+ * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and
+ * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
+ * the current state of tethering. Each include a list of
+ * interface names in that state (may be empty).
+ */
+ public static final String ACTION_TETHER_STATE_CHANGED =
+ "android.net.conn.TETHER_STATE_CHANGED";
+
+ /**
+ * gives a String[] listing all the interfaces configured for
+ * tethering and currently available for tethering.
+ */
+ public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+
+ /**
+ * gives a String[] listing all the interfaces currently in local-only
+ * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
+ */
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+
+ /**
+ * gives a String[] listing all the interfaces currently tethered
+ * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
+ */
+ public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+
+ /**
+ * gives a String[] listing all the interfaces we tried to tether and
+ * failed. Use {@link #getLastTetherError} to find the error code
+ * for any interfaces listed here.
+ */
+ public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+
+ /**
+ * Invalid tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_INVALID = -1;
+
+ /**
+ * Wifi tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_WIFI = 0;
+
+ /**
+ * USB tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_USB = 1;
+
+ /**
+ * Bluetooth tethering type.
+ * @see #startTethering.
+ */
+ public static final int TETHERING_BLUETOOTH = 2;
+
+ /**
+ * Wifi P2p tethering type.
+ * Wifi P2p tethering is set through events automatically, and don't
+ * need to start from #startTethering.
+ */
+ public static final int TETHERING_WIFI_P2P = 3;
+
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering to
+ * enable if any.
+ */
+ public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering for
+ * which to cancel provisioning.
+ */
+ public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+
+ /**
+ * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+ * provisioning.
+ */
+ public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+
+ /**
+ * Tells the TetherService to run a provision check now.
+ */
+ public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+
+ /**
+ * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
+ * which will receive provisioning results. Can be left empty.
+ */
+ public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+
public static final int TETHER_ERROR_NO_ERROR = 0;
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
@@ -470,7 +565,7 @@ public class TetheringManager {
* failed. Re-attempting to tether may cause them to reset to the Tethered
* state. Alternatively, causing the interface to be destroyed and recreated
* may cause them to reset to the available state.
- * {@link ConnectivityManager#getLastTetherError} can be used to get more
+ * {@link TetheringManager#getLastTetherError} can be used to get more
* information on the cause of the errors.
*
* @return an array of 0 or more String indicating the interface names
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index abfb33c7af9e..6ac467e39a9d 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -24,25 +24,24 @@ import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
import static android.net.util.NetworkConstants.asByte;
import static android.net.util.TetheringMessageBase.BASE_IPSERVER;
-import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkStackStatusCallback;
import android.net.INetworkStatsService;
-import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
+import android.net.TetheringManager;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.DhcpServingParamsParcelExt;
import android.net.dhcp.IDhcpServer;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.net.shared.NetdUtils;
+import android.net.shared.RouteUtils;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
-import android.net.util.NetdService;
import android.net.util.SharedLog;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
@@ -119,7 +118,7 @@ public class IpServer extends StateMachine {
*
* @param who the calling instance of IpServer
* @param state one of STATE_*
- * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+ * @param lastError one of TetheringManager.TETHER_ERROR_*
*/
public void updateInterfaceState(IpServer who, int state, int lastError) { }
@@ -144,10 +143,6 @@ public class IpServer extends StateMachine {
return InterfaceParams.getByName(ifName);
}
- public INetd getNetdService() {
- return NetdService.getInstance();
- }
-
/** Create a DhcpServer instance to be used by IpServer. */
public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb);
@@ -180,7 +175,6 @@ public class IpServer extends StateMachine {
private final State mUnavailableState;
private final SharedLog mLog;
- private final INetworkManagementService mNMService;
private final INetd mNetd;
private final INetworkStatsService mStatsService;
private final Callback mCallback;
@@ -210,15 +204,15 @@ public class IpServer extends StateMachine {
private int mDhcpServerStartIndex = 0;
private IDhcpServer mDhcpServer;
private RaParams mLastRaParams;
+ private LinkAddress mIpv4Address;
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetworkManagementService nMService, INetworkStatsService statsService,
- Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
+ INetd netd, INetworkStatsService statsService, Callback callback,
+ boolean usingLegacyDhcp, Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
- mNMService = nMService;
- mNetd = deps.getNetdService();
+ mNetd = netd;
mStatsService = statsService;
mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
@@ -228,7 +222,7 @@ public class IpServer extends StateMachine {
mUsingLegacyDhcp = usingLegacyDhcp;
mDeps = deps;
resetLinkProperties();
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
mServingMode = STATE_AVAILABLE;
mInitialState = new InitialState();
@@ -249,7 +243,7 @@ public class IpServer extends StateMachine {
}
/**
- * Tethering downstream type. It would be one of ConnectivityManager#TETHERING_*.
+ * Tethering downstream type. It would be one of TetheringManager#TETHERING_*.
*/
public int interfaceType() {
return mInterfaceType;
@@ -347,13 +341,13 @@ public class IpServer extends StateMachine {
}
});
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw new IllegalStateException(e);
}
});
}
private void handleError() {
- mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
transitionTo(mInitialState);
}
}
@@ -388,14 +382,15 @@ public class IpServer extends StateMachine {
public void callback(int statusCode) {
if (statusCode != STATUS_SUCCESS) {
mLog.e("Error stopping DHCP server: " + statusCode);
- mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
// Not much more we can do here
}
}
});
mDhcpServer = null;
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ mLog.e("Error stopping DHCP", e);
+ // Not much more we can do here
}
}
}
@@ -414,85 +409,69 @@ public class IpServer extends StateMachine {
// NOTE: All of configureIPv4() will be refactored out of existence
// into calls to InterfaceController, shared with startIPv4().
mInterfaceCtrl.clearIPv4Address();
+ mIpv4Address = null;
}
- // TODO: Refactor this in terms of calls to InterfaceController.
private boolean configureIPv4(boolean enabled) {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
// TODO: Replace this hard-coded information with dynamically selected
// config passed down to us by a higher layer IP-coordinating element.
- String ipAsString = null;
+ final Inet4Address srvAddr;
int prefixLen = 0;
- if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
- ipAsString = USB_NEAR_IFACE_ADDR;
- prefixLen = USB_PREFIX_LENGTH;
- } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
- ipAsString = getRandomWifiIPv4Address();
- prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
- } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) {
- ipAsString = WIFI_P2P_IFACE_ADDR;
- prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
- } else {
- // BT configures the interface elsewhere: only start DHCP.
- final Inet4Address srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
- return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
- }
-
- final LinkAddress linkAddr;
try {
- final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
- if (ifcg == null) {
- mLog.e("Received null interface config");
- return false;
- }
-
- InetAddress addr = parseNumericAddress(ipAsString);
- linkAddr = new LinkAddress(addr, prefixLen);
- ifcg.setLinkAddress(linkAddr);
- if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
- // The WiFi stack has ownership of the interface up/down state.
- // It is unclear whether the Bluetooth or USB stacks will manage their own
- // state.
- ifcg.ignoreInterfaceUpDownStatus();
+ if (mInterfaceType == TetheringManager.TETHERING_USB) {
+ srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
+ prefixLen = USB_PREFIX_LENGTH;
+ } else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+ srvAddr = (Inet4Address) parseNumericAddress(getRandomWifiIPv4Address());
+ prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
+ } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
+ srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
+ prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
} else {
- if (enabled) {
- ifcg.setInterfaceUp();
- } else {
- ifcg.setInterfaceDown();
- }
+ // BT configures the interface elsewhere: only start DHCP.
+ // TODO: make all tethering types behave the same way, and delete the bluetooth
+ // code that calls into NetworkManagementService directly.
+ srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
+ mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
+ return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
}
- ifcg.clearFlag("running");
+ mIpv4Address = new LinkAddress(srvAddr, prefixLen);
+ } catch (IllegalArgumentException e) {
+ mLog.e("Error selecting ipv4 address", e);
+ if (!enabled) stopDhcp();
+ return false;
+ }
- // TODO: this may throw if the interface is already gone. Do proper handling and
- // simplify the DHCP server start/stop.
- mNMService.setInterfaceConfig(mIfaceName, ifcg);
+ final Boolean setIfaceUp;
+ if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+ // The WiFi stack has ownership of the interface up/down state.
+ // It is unclear whether the Bluetooth or USB stacks will manage their own
+ // state.
+ setIfaceUp = null;
+ } else {
+ setIfaceUp = enabled;
+ }
+ if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) {
+ mLog.e("Error configuring interface");
+ if (!enabled) stopDhcp();
+ return false;
+ }
- if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
- return false;
- }
- } catch (Exception e) {
- mLog.e("Error configuring interface " + e);
- if (!enabled) {
- try {
- // Calling stopDhcp several times is fine
- stopDhcp();
- } catch (Exception dhcpError) {
- mLog.e("Error stopping DHCP", dhcpError);
- }
- }
+ if (!configureDhcp(enabled, srvAddr, prefixLen)) {
return false;
}
// Directly-connected route.
- final IpPrefix ipv4Prefix = new IpPrefix(linkAddr.getAddress(),
- linkAddr.getPrefixLength());
+ final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
+ mIpv4Address.getPrefixLength());
final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST);
if (enabled) {
- mLinkProperties.addLinkAddress(linkAddr);
+ mLinkProperties.addLinkAddress(mIpv4Address);
mLinkProperties.addRoute(route);
} else {
- mLinkProperties.removeLinkAddress(linkAddr);
+ mLinkProperties.removeLinkAddress(mIpv4Address);
mLinkProperties.removeRoute(route);
}
return true;
@@ -584,14 +563,12 @@ public class IpServer extends StateMachine {
if (!deprecatedPrefixes.isEmpty()) {
final ArrayList<RouteInfo> toBeRemoved =
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
- try {
- final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
- if (removalFailures > 0) {
- mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
- removalFailures));
- }
- } catch (RemoteException e) {
- mLog.e("Failed to remove IPv6 routes from local table: " + e);
+ // Remove routes from local network.
+ final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork(
+ mNetd, toBeRemoved);
+ if (removalFailures > 0) {
+ mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
+ removalFailures));
}
for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
@@ -608,13 +585,18 @@ public class IpServer extends StateMachine {
final ArrayList<RouteInfo> toBeAdded =
getLocalRoutesFor(mIfaceName, addedPrefixes);
try {
- // It's safe to call addInterfaceToLocalNetwork() even if
- // the interface is already in the local_network. Note also
- // that adding routes that already exist does not cause an
- // error (EEXIST is silently ignored).
- mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
- } catch (Exception e) {
- mLog.e("Failed to add IPv6 routes to local table: " + e);
+ // It's safe to call networkAddInterface() even if
+ // the interface is already in the local_network.
+ mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName);
+ try {
+ // Add routes from local network. Note that adding routes that
+ // already exist does not cause an error (EEXIST is silently ignored).
+ RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded);
+ } catch (IllegalStateException e) {
+ mLog.e("Failed to add IPv6 routes to local table: " + e);
+ }
+ } catch (ServiceSpecificException | RemoteException e) {
+ mLog.e("Failed to add " + mIfaceName + " to local table: ", e);
}
for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
@@ -728,7 +710,7 @@ public class IpServer extends StateMachine {
logMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) {
case STATE_LOCAL_ONLY:
transitionTo(mLocalHotspotState);
@@ -757,15 +739,17 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
if (!startIPv4()) {
- mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
return;
}
try {
- mNMService.tetherInterface(mIfaceName);
- } catch (Exception e) {
+ final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
+ mIpv4Address.getPrefixLength());
+ NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e("Error Tethering: " + e);
- mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
@@ -784,9 +768,9 @@ public class IpServer extends StateMachine {
stopIPv6();
try {
- mNMService.untetherInterface(mIfaceName);
- } catch (Exception e) {
- mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+ NetdUtils.untetherInterface(mNetd, mIfaceName);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
mLog.e("Failed to untether interface: " + e);
}
@@ -816,7 +800,7 @@ public class IpServer extends StateMachine {
case CMD_START_TETHERING_ERROR:
case CMD_STOP_TETHERING_ERROR:
case CMD_SET_DNS_FORWARDERS_ERROR:
- mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_MASTER_ERROR;
transitionTo(mInitialState);
break;
default:
@@ -835,7 +819,7 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
super.enter();
- if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
transitionTo(mInitialState);
}
@@ -871,7 +855,7 @@ public class IpServer extends StateMachine {
@Override
public void enter() {
super.enter();
- if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
transitionTo(mInitialState);
}
@@ -901,17 +885,17 @@ public class IpServer extends StateMachine {
// About to tear down NAT; gather remaining statistics.
mStatsService.forceUpdate();
} catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
+ mLog.e("Exception in forceUpdate: " + e.toString());
}
try {
- mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
+ mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString());
}
try {
- mNMService.disableNat(mIfaceName, upstreamIface);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
+ mNetd.tetherRemoveForward(mIfaceName, upstreamIface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception in disableNat: " + e.toString());
}
}
@@ -947,12 +931,12 @@ public class IpServer extends StateMachine {
for (String ifname : added) {
try {
- mNMService.enableNat(mIfaceName, ifname);
- mNMService.startInterfaceForwarding(mIfaceName, ifname);
- } catch (Exception e) {
- mLog.e("Exception enabling NAT: " + e);
+ mNetd.tetherAddForward(mIfaceName, ifname);
+ mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception enabling NAT: " + e.toString());
cleanupUpstream();
- mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
return true;
}
@@ -997,7 +981,7 @@ public class IpServer extends StateMachine {
class UnavailableState extends State {
@Override
public void enter() {
- mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
sendInterfaceState(STATE_UNAVAILABLE);
}
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 7e685fbe97f1..ce6657334611 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -16,16 +16,16 @@
package com.android.server.connectivity.tethering;
-import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
-import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_INVALID;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringManager.EXTRA_RUN_PROVISION;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static com.android.internal.R.string.config_wifi_tether_enable;
@@ -59,7 +59,7 @@ import java.io.PrintWriter;
/**
* Re-check tethering provisioning for enabled downstream tether types.
- * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+ * Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* All methods of this class must be accessed from the thread of tethering
* state machine.
@@ -86,9 +86,9 @@ public class EntitlementManager {
private static final int EVENT_GET_ENTITLEMENT_VALUE = 4;
// The ArraySet contains enabled downstream types, ex:
- // {@link ConnectivityManager.TETHERING_WIFI}
- // {@link ConnectivityManager.TETHERING_USB}
- // {@link ConnectivityManager.TETHERING_BLUETOOTH}
+ // {@link TetheringManager.TETHERING_WIFI}
+ // {@link TetheringManager.TETHERING_USB}
+ // {@link TetheringManager.TETHERING_BLUETOOTH}
private final ArraySet<Integer> mCurrentTethers;
private final Context mContext;
private final int mPermissionChangeMessageCode;
@@ -96,8 +96,8 @@ public class EntitlementManager {
private final SparseIntArray mEntitlementCacheValue;
private final EntitlementHandler mHandler;
private final StateMachine mTetherMasterSM;
- // Key: ConnectivityManager.TETHERING_*(downstream).
- // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
+ // Key: TetheringManager.TETHERING_*(downstream).
+ // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
private final SparseIntArray mCellularPermitted;
private PendingIntent mProvisioningRecheckAlarm;
private boolean mCellularUpstreamPermitted = true;
@@ -133,7 +133,7 @@ public class EntitlementManager {
/**
* Ui entitlement check fails in |downstream|.
*
- * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
+ * @param downstream tethering type from TetheringManager.TETHERING_{@code *}.
*/
void onUiEntitlementFailed(int downstream);
}
@@ -169,7 +169,7 @@ public class EntitlementManager {
* This is called when tethering starts.
* Launch provisioning app if upstream is cellular.
*
- * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *}
* @param showProvisioningUi a boolean indicating whether to show the
* provisioning app UI if there is one.
*/
@@ -210,7 +210,7 @@ public class EntitlementManager {
/**
* Tell EntitlementManager that a given type of tethering has been disabled
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
public void stopProvisioningIfNeeded(int type) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0));
@@ -296,7 +296,7 @@ public class EntitlementManager {
/**
* Re-check tethering provisioning for all enabled tether types.
- * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+ * Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* @param config an object that encapsulates the various tethering configuration elements.
* Note: this method is only called from TetherMaster on the handler thread.
@@ -363,7 +363,7 @@ public class EntitlementManager {
/**
* Run no UI tethering provisioning check.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
*/
@VisibleForTesting
@@ -390,7 +390,7 @@ public class EntitlementManager {
/**
* Run the UI-enabled tethering provisioning check.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
* @param receiver to receive entitlement check result.
*/
@@ -461,7 +461,7 @@ public class EntitlementManager {
* Add the mapping between provisioning result and tethering type.
* Notify UpstreamNetworkMonitor if Cellular permission changes.
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param resultCode Provisioning result
*/
protected void addDownstreamMapping(int type, int resultCode) {
@@ -476,7 +476,7 @@ public class EntitlementManager {
/**
* Remove the mapping for input tethering type.
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
*/
protected void removeDownstreamMapping(int type) {
mLog.i("removeDownstreamMapping: " + type);
@@ -625,7 +625,7 @@ public class EntitlementManager {
/**
* Update the last entitlement value to internal cache
*
- * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param resultCode last entitlement value
* @return the last updated entitlement value
*/
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index 38fa91e7387e..ce7c2a669f0a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -279,7 +279,7 @@ public class OffloadController {
entry.iface = kv.getKey();
entry.rxBytes = value.rxBytes;
entry.txBytes = value.txBytes;
- stats.addValues(entry);
+ stats.addEntry(entry);
}
return stats;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 5b267046a851..4b860d0bd91e 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -20,23 +20,23 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_INVALID;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
-import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
+import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.util.TetheringMessageBase.BASE_MASTER;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -75,6 +75,7 @@ import android.net.NetworkUtils;
import android.net.TetherStatesParcel;
import android.net.TetheringConfigurationParcel;
import android.net.ip.IpServer;
+import android.net.shared.NetdUtils;
import android.net.util.BaseNetdUnsolicitedEventListener;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
@@ -87,12 +88,12 @@ import android.net.wifi.p2p.WifiP2pManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.PhoneStateListener;
@@ -102,6 +103,9 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -139,6 +143,8 @@ public class Tethering {
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(sMessageClasses);
+ // Keep in sync with NETID_UNSET in system/netd/include/netid_client.h
+ private static final int NETID_UNSET = 0;
private static class TetherState {
public final IpServer ipServer;
@@ -172,8 +178,6 @@ public class Tethering {
private final Context mContext;
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
- // Stopship: replace mNMService before production.
- private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
private final INetworkPolicyManager mPolicyManager;
private final Looper mLooper;
@@ -210,7 +214,6 @@ public class Tethering {
mLog.mark("Tethering.constructed");
mDeps = deps;
mContext = mDeps.getContext();
- mNMService = mDeps.getINetworkManagementService();
mStatsService = mDeps.getINetworkStatsService();
mPolicyManager = mDeps.getINetworkPolicyManager();
mNetd = mDeps.getINetd(mContext);
@@ -225,10 +228,9 @@ public class Tethering {
mHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(mHandler,
- mDeps.getOffloadHardwareInterface(mHandler, mLog),
- mContext.getContentResolver(), mNMService,
- mLog);
- mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
+ mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(),
+ mDeps.getINetworkManagementService(), mLog);
+ mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
@@ -421,7 +423,6 @@ public class Tethering {
}
}
-
void interfaceRemoved(String iface) {
if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
synchronized (mPublicSync) {
@@ -1022,8 +1023,8 @@ public class Tethering {
String[] ifaces = null;
try {
- ifaces = mNMService.listInterfaces();
- } catch (Exception e) {
+ ifaces = mNetd.interfaceGetList();
+ } catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Error listing Interfaces", e);
return;
}
@@ -1282,25 +1283,25 @@ public class Tethering {
protected boolean turnOnMasterTetherSettings() {
final TetheringConfiguration cfg = mConfig;
try {
- mNMService.setIpForwardingEnabled(true);
- } catch (Exception e) {
+ mNetd.ipfwdEnableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
+
// TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
// Legacy DHCP server is disabled if passed an empty ranges array
final String[] dhcpRanges = cfg.enableLegacyDhcpServer
- ? cfg.legacyDhcpRanges
- : new String[0];
+ ? cfg.legacyDhcpRanges : new String[0];
try {
- // TODO: Find a more accurate method name (startDHCPv4()?).
- mNMService.startTethering(dhcpRanges);
- } catch (Exception e) {
+ NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
+ } catch (RemoteException | ServiceSpecificException e) {
try {
- mNMService.stopTethering();
- mNMService.startTethering(dhcpRanges);
- } catch (Exception ee) {
+ // Stop and retry.
+ mNetd.tetherStop();
+ NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
+ } catch (RemoteException | ServiceSpecificException ee) {
mLog.e(ee);
transitionTo(mStartTetheringErrorState);
return false;
@@ -1312,15 +1313,15 @@ public class Tethering {
protected boolean turnOffMasterTetherSettings() {
try {
- mNMService.stopTethering();
- } catch (Exception e) {
+ mNetd.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mStopTetheringErrorState);
return false;
}
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) {
mLog.e(e);
transitionTo(mSetIpForwardingDisabledErrorState);
return false;
@@ -1390,12 +1391,13 @@ public class Tethering {
// TODO: remove this invocation of NetworkUtils.makeStrings().
dnsServers = NetworkUtils.makeStrings(dnses);
}
+ final int netId = (network != null) ? network.netId : NETID_UNSET;
try {
- mNMService.setDnsForwarders(network, dnsServers);
+ mNetd.tetherDnsSet(netId, dnsServers);
mLog.log(String.format(
"SET DNS forwarders: network=%s dnsServers=%s",
network, Arrays.toString(dnsServers)));
- } catch (Exception e) {
+ } catch (RemoteException | ServiceSpecificException e) {
// TODO: Investigate how this can fail and what exactly
// happens if/when such failures occur.
mLog.e("setting DNS forwarders failed, " + e);
@@ -1698,8 +1700,8 @@ public class Tethering {
Log.e(TAG, "Error in startTethering");
notify(IpServer.CMD_START_TETHERING_ERROR);
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1709,8 +1711,8 @@ public class Tethering {
Log.e(TAG, "Error in stopTethering");
notify(IpServer.CMD_STOP_TETHERING_ERROR);
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1720,11 +1722,11 @@ public class Tethering {
Log.e(TAG, "Error in setDnsForwarders");
notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
try {
- mNMService.stopTethering();
- } catch (Exception e) { }
+ mNetd.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) { }
try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) { }
+ mNetd.ipfwdDisableForwarding(TAG);
+ } catch (RemoteException | ServiceSpecificException e) { }
}
}
@@ -1884,7 +1886,7 @@ public class Tethering {
}
}
- void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -2065,7 +2067,7 @@ public class Tethering {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
- new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+ new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mStatsService,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index fd2f708aea30..65a0ac13a84b 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -16,13 +16,14 @@
package android.net.ip;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+import static android.net.INetd.IF_STATE_UP;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.ip.IpServer.STATE_AVAILABLE;
import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
@@ -52,7 +53,7 @@ import static org.mockito.Mockito.when;
import android.net.INetd;
import android.net.INetworkStatsService;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -64,7 +65,6 @@ import android.net.dhcp.IDhcpServerCallbacks;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
-import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.text.TextUtils;
@@ -89,6 +89,8 @@ public class IpServerTest {
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
+ private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1";
+ private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
private static final int DHCP_LEASE_TIME_SECS = 3600;
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
@@ -96,11 +98,9 @@ public class IpServerTest {
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
- @Mock private INetworkManagementService mNMService;
@Mock private INetd mNetd;
@Mock private INetworkStatsService mStatsService;
@Mock private IpServer.Callback mCallback;
- @Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private SharedLog mSharedLog;
@Mock private IDhcpServer mDhcpServer;
@Mock private RouterAdvertisementDaemon mRaDaemon;
@@ -112,6 +112,7 @@ public class IpServerTest {
private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
private IpServer mIpServer;
+ private InterfaceConfigurationParcel mInterfaceConfiguration;
private void initStateMachine(int interfaceType) throws Exception {
initStateMachine(interfaceType, false /* usingLegacyDhcp */);
@@ -131,17 +132,20 @@ public class IpServerTest {
}).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
- when(mDependencies.getNetdService()).thenReturn(mNetd);
-
+ mInterfaceConfiguration = new InterfaceConfigurationParcel();
+ mInterfaceConfiguration.flags = new String[0];
+ if (interfaceType == TETHERING_BLUETOOTH) {
+ mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR;
+ mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH;
+ }
mIpServer = new IpServer(
- IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
- mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+ IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mStatsService,
+ mCallback, usingLegacyDhcp, mDependencies);
mIpServer.start();
// Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll();
- reset(mNMService, mStatsService, mCallback);
- when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
+ reset(mNetd, mStatsService, mCallback);
when(mRaDaemon.start()).thenReturn(true);
}
@@ -158,8 +162,7 @@ public class IpServerTest {
if (upstreamIface != null) {
dispatchTetherConnectionChanged(upstreamIface);
}
- reset(mNMService, mStatsService, mCallback);
- when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
+ reset(mNetd, mStatsService, mCallback);
}
@Before public void setUp() throws Exception {
@@ -169,15 +172,14 @@ public class IpServerTest {
@Test
public void startsOutAvailable() {
- mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
- false /* usingLegacyDhcp */, mDependencies);
+ mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
+ mNetd, mStatsService, mCallback, false /* usingLegacyDhcp */, mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
+ verifyNoMoreInteractions(mCallback, mNetd, mStatsService);
}
@Test
@@ -196,7 +198,7 @@ public class IpServerTest {
// None of these commands should trigger us to request action from
// the rest of the system.
dispatchCommand(command);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
}
@@ -208,7 +210,7 @@ public class IpServerTest {
verify(mCallback).updateInterfaceState(
mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -216,13 +218,17 @@ public class IpServerTest {
initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ // One for ipv4 route, one for ipv6 link local route.
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -230,14 +236,16 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback);
- inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
+ inOrder.verify(mNetd).tetherApplyDnsInterfaces();
+ inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
+ inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -245,16 +253,19 @@ public class IpServerTest {
initStateMachine(TETHERING_USB);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
- inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -262,16 +273,19 @@ public class IpServerTest {
initStateMachine(TETHERING_WIFI_P2P);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
- InOrder inOrder = inOrder(mCallback, mNMService);
- inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
- inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
- inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ InOrder inOrder = inOrder(mCallback, mNetd);
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+ inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -281,10 +295,10 @@ public class IpServerTest {
// Telling the state machine about its upstream interface triggers
// a little more configuration.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- InOrder inOrder = inOrder(mNMService);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ InOrder inOrder = inOrder(mNetd);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -292,49 +306,49 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
public void handlesChangingUpstreamNatFailure() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@Test
public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
+ doThrow(RemoteException.class).when(mNetd).ipfwdAddInterfaceForward(
IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
- InOrder inOrder = inOrder(mNMService, mStatsService);
+ InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@Test
@@ -342,17 +356,19 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback);
+ InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
inOrder.verify(mStatsService).forceUpdate();
- inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
- inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+ inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNetd).tetherApplyDnsInterfaces();
+ inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
+ inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
@Test
@@ -361,13 +377,14 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_USB, null);
if (shouldThrow) {
- doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
+ doThrow(RemoteException.class).when(mNetd).tetherInterfaceRemove(IFACE_NAME);
}
dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(
- IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ // Currently IpServer interfaceSetCfg twice to stop IPv4. One just set interface down
+ // Another one is set IPv4 to 0.0.0.0/0 as clearng ipv4 address.
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -380,12 +397,15 @@ public class IpServerTest {
public void usbShouldBeTornDownOnTetherError() throws Exception {
initStateMachine(TETHERING_USB);
- doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
+ doThrow(RemoteException.class).when(mNetd).tetherInterfaceAdd(IFACE_NAME);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(
- IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ usbTeardownOrder.verify(mNetd).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
+ usbTeardownOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
+
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -397,11 +417,13 @@ public class IpServerTest {
public void shouldTearDownUsbOnUpstreamError() throws Exception {
initTetheredStateMachine(TETHERING_USB, null);
- doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
+ doThrow(RemoteException.class).when(mNetd).tetherAddForward(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
- usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
- usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
+ InOrder usbTeardownOrder = inOrder(mNetd, mCallback);
+ usbTeardownOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
+
+ usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
+ argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
usbTeardownOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
usbTeardownOrder.verify(mCallback).updateLinkProperties(
@@ -413,11 +435,11 @@ public class IpServerTest {
public void ignoresDuplicateUpstreamNotifications() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
for (int i = 0; i < 5; i++) {
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
}
}
@@ -525,4 +547,12 @@ public class IpServerTest {
// never see an empty interface name in any LinkProperties update.
assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
}
+
+ private boolean assertContainsFlag(String[] flags, String match) {
+ for (String flag : flags) {
+ if (flag.equals(match)) return true;
+ }
+ fail("Missing flag: " + match);
+ return false;
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 99cf9e90d912..66eba9ae3b7a 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -16,12 +16,12 @@
package com.android.server.connectivity.tethering;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 04b2eb411c9d..7af48a89d87c 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -19,16 +19,15 @@ package com.android.server.connectivity.tethering;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
+import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -50,7 +49,6 @@ import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -74,14 +72,13 @@ import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.TetherStatesParcel;
@@ -147,6 +144,7 @@ public class TetheringTest {
private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0";
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
+ private static final String TETHERING_NAME = "Tethering";
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@@ -185,6 +183,7 @@ public class TetheringTest {
private BroadcastReceiver mBroadcastReceiver;
private Tethering mTethering;
private PhoneStateListener mPhoneStateListener;
+ private InterfaceConfigurationParcel mInterfaceConfiguration;
private class TestContext extends BroadcastInterceptingContext {
TestContext(Context base) {
@@ -248,11 +247,6 @@ public class TetheringTest {
}
@Override
- public INetd getNetdService() {
- return mNetd;
- }
-
- @Override
public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb) {
new Thread(() -> {
@@ -429,11 +423,11 @@ public class TetheringTest {
.thenReturn(new int[0]);
when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
.thenReturn(false);
- when(mNMService.listInterfaces())
+ when(mNetd.interfaceGetList())
.thenReturn(new String[] {
TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
- when(mNMService.getInterfaceConfig(anyString()))
- .thenReturn(new InterfaceConfiguration());
+ mInterfaceConfiguration = new InterfaceConfigurationParcel();
+ mInterfaceConfiguration.flags = new String[0];
when(mRouterAdvertisementDaemon.start())
.thenReturn(true);
@@ -495,15 +489,12 @@ public class TetheringTest {
p2pInfo.groupFormed = isGroupFormed;
p2pInfo.isGroupOwner = isGroupOwner;
- NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
-
WifiP2pGroup group = new WifiP2pGroup();
group.setIsGroupOwner(isGroupOwner);
group.setInterface(ifname);
final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
- intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
@@ -523,10 +514,11 @@ public class TetheringTest {
}
private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
- verify(mNMService, times(1)).getInterfaceConfig(ifname);
- verify(mNMService, times(1))
- .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(ifname);
+ verify(mNetd, times(1)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherInterfaceAdd(ifname);
+ verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, ifname);
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname),
+ anyString(), anyString());
}
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
@@ -558,7 +550,7 @@ public class TetheringTest {
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
}
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
}
@@ -581,14 +573,14 @@ public class TetheringTest {
prepareUsbTethering(upstreamState);
// This should produce no activity of any kind.
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Pretend we then receive USB configured broadcast.
sendUsbBroadcast(true, true, true);
mLooper.dispatchAll();
// Now we should see the start of tethering mechanics (in this case:
// tetherMatchingInterfaces() which starts by fetching all interfaces).
- verify(mNMService, times(1)).listInterfaces();
+ verify(mNetd, times(1)).interfaceGetList();
// UpstreamNetworkMonitor should receive selected upstream
verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
@@ -618,9 +610,9 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verifyNoMoreInteractions(mNetd);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -638,16 +630,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mWifiManager, times(3)).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
@@ -684,8 +676,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
@@ -708,8 +700,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -721,8 +713,8 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mRouterAdvertisementDaemon, times(1)).start();
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
@@ -736,12 +728,11 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobile464xlatUpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
- TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -754,9 +745,9 @@ public class TetheringTest {
UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState();
runUsbTethering(upstreamState);
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// Then 464xlat comes up
upstreamState = buildMobile464xlatUpstreamState();
@@ -772,12 +763,11 @@ public class TetheringTest {
mLooper.dispatchAll();
// Forwarding is added for 464xlat
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
- TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
// Forwarding was not re-added for v6 (still times(1))
- verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
- verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// DHCP not restarted on downstream (still times(1))
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
}
@@ -820,7 +810,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -833,7 +823,7 @@ public class TetheringTest {
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
}
@@ -847,7 +837,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -858,9 +848,11 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
+ anyString(), anyString());
+ verifyNoMoreInteractions(mNetd);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -878,8 +870,8 @@ public class TetheringTest {
/////
// We do not currently emulate any upstream being found.
//
- // This is why there are no calls to verify mNMService.enableNat() or
- // mNMService.startInterfaceForwarding().
+ // This is why there are no calls to verify mNetd.tetherAddForward() or
+ // mNetd.ipfwdAddInterfaceForward().
/////
// Emulate pressing the WiFi tethering button.
@@ -887,7 +879,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, when tethering mode
// is being torn down.
@@ -895,16 +887,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, atLeastOnce())
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice for disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mWifiManager, times(3)).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
@@ -915,14 +907,14 @@ public class TetheringTest {
@Test
public void failureEnablingIpForwarding() throws Exception {
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
- doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
+ doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -931,15 +923,15 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
- // We verify get/set called thrice here: twice for setup (on NMService) and once during
- // teardown (on Netd) because all events happen over the course of the single
+ // We verify get/set called three times here: twice for setup and once during
+ // teardown because all events happen over the course of the single
// dispatchAll() above. Note that once the IpServer IPv4 address config
// code is refactored the two calls during shutdown will revert to one.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
- verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
+ verify(mNetd, times(3)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
+ verify(mNetd, times(1)).tetherInterfaceAdd(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
+ anyString(), anyString());
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
@@ -949,18 +941,20 @@ public class TetheringTest {
assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
// This never gets called because of the exception thrown above.
- verify(mNMService, times(0)).startTethering(any(String[].class));
+ verify(mNetd, times(0)).tetherStartWithConfiguration(any());
// When the master state machine transitions to an error state it tells
// downstream interfaces, which causes us to tell Wi-Fi about the error
// so it can take down AP mode.
- verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
}
private void runUserRestrictionsChange(
@@ -1232,9 +1226,9 @@ public class TetheringTest {
verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNMService, times(1)).setIpForwardingEnabled(true);
- verify(mNMService, times(1)).startTethering(any(String[].class));
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, times(1)).tetherStartWithConfiguration(any());
+ verifyNoMoreInteractions(mNetd);
verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
@@ -1249,16 +1243,16 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
- // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
- verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, times(2))
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).stopTethering();
- verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ verify(mNetd, times(1)).tetherInterfaceRemove(TEST_P2P_IFNAME);
+ verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice for disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, times(1)).tetherStop();
+ verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
- verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mNetd);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
@@ -1272,12 +1266,11 @@ public class TetheringTest {
sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).setIpForwardingEnabled(true);
- verify(mNMService, never()).startTethering(any(String[].class));
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, never()).tetherStartWithConfiguration(any());
// Emulate externally-visible WifiP2pManager effects, when wifi p2p group
// is being removed.
@@ -1285,13 +1278,13 @@ public class TetheringTest {
mTethering.interfaceRemoved(TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).stopTethering();
- verify(mNMService, never()).setIpForwardingEnabled(false);
- verifyNoMoreInteractions(mNMService);
+ verify(mNetd, never()).tetherApplyDnsInterfaces();
+ verify(mNetd, never()).tetherInterfaceRemove(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherStop();
+ verify(mNetd, never()).ipfwdDisableForwarding(TETHERING_NAME);
+ verifyNoMoreInteractions(mNetd);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
@@ -1321,12 +1314,11 @@ public class TetheringTest {
sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
mLooper.dispatchAll();
- verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
- verify(mNMService, never())
- .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
- verify(mNMService, never()).setIpForwardingEnabled(true);
- verify(mNMService, never()).startTethering(any(String[].class));
+ verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME);
+ verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME);
+ verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd, never()).tetherStartWithConfiguration(any());
assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
}
@Test
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 46c49e5a5e11..39efe731ce8a 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -447,44 +447,33 @@ public class RenderScript {
validate();
return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
}
- native long rsnAllocationCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+
+ native long rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(), usage);
+ return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp,
int usage) {
validate();
- return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp.getNativeInstance(),
- usage);
+ return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
}
- native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+ native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp,
int usage);
synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
validate();
- return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(),
- usage);
- }
- native long rsnAllocationCreateBitmapRef(long con, long type, long bitmapHandle);
- synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
- validate();
- return rsnAllocationCreateBitmapRef(mContext, type, bmp.getNativeInstance());
- }
- native long rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
- synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
- validate();
- return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
+ return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
}
- native void rsnAllocationCopyToBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyToBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyToBitmap(mContext, alloc, bmp);
}
native void rsnAllocationSyncAll(long con, long alloc, int src);
@@ -537,10 +526,10 @@ public class RenderScript {
validate();
rsnAllocationGenerateMipmaps(mContext, alloc);
}
- native void rsnAllocationCopyFromBitmap(long con, long alloc, long bitmapHandle);
+ native void rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
validate();
- rsnAllocationCopyFromBitmap(mContext, alloc, bmp.getNativeInstance());
+ rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0854b9582187..f9ef0b7b8e9d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -12,7 +12,6 @@ LOCAL_SHARED_LIBRARIES := \
libRS \
libcutils \
liblog \
- libhwui \
libutils \
libui \
libgui \
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index dfee96182a48..5ae895dbbce6 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -32,10 +32,10 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
+#include <android/graphics/bitmap.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_runtime/android_util_AssetManager.h"
-#include "android/graphics/GraphicsJNI.h"
#include "android/native_window.h"
#include "android/native_window_jni.h"
@@ -1319,27 +1319,28 @@ nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
rsAllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
}
+static size_t computeByteSize(const android::graphics::Bitmap& bitmap) {
+ AndroidBitmapInfo info = bitmap.getInfo();
+ return info.height * info.stride;
+}
+
static jlong
nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static jlong
nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
- jint mip, jlong bitmapPtr, jint usage)
+ jint mip, jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
@@ -1349,40 +1350,35 @@ nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con,
static jlong
nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
- jlong bitmapPtr, jint usage)
+ jobject jbitmap, jint usage)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
const void* ptr = bitmap.getPixels();
jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
(RsType)type, (RsAllocationMipmapControl)mip,
- ptr, bitmap.computeByteSize(), usage);
+ ptr, computeByteSize(bitmap), usage);
return id;
}
static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
- int w = bitmap.width();
- int h = bitmap.height();
+ android::graphics::Bitmap bitmap(_env, jbitmap);
+ int w = bitmap.getInfo().width;
+ int h = bitmap.getInfo().height;
const void* ptr = bitmap.getPixels();
rsAllocation2DData((RsContext)con, (RsAllocation)alloc, 0, 0,
0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X,
- w, h, ptr, bitmap.computeByteSize(), 0);
+ w, h, ptr, computeByteSize(bitmap), 0);
}
static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
+nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
{
- SkBitmap bitmap;
- bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
-
+ android::graphics::Bitmap bitmap(_env, jbitmap);
void* ptr = bitmap.getPixels();
- rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, bitmap.computeByteSize());
+ rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, computeByteSize(bitmap));
bitmap.notifyPixelsChanged();
}
@@ -2867,12 +2863,12 @@ static const JNINativeMethod methods[] = {
{"rsnTypeGetNativeData", "(JJ[J)V", (void*)nTypeGetNativeData },
{"rsnAllocationCreateTyped", "(JJIIJ)J", (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap", "(JJIJI)J", (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation", "(JJIJI)J", (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJIJI)J", (void*)nAllocationCubeCreateFromBitmap },
+{"rsnAllocationCreateFromBitmap", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateFromBitmap },
+{"rsnAllocationCreateBitmapBackedAllocation", "(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCreateBitmapBackedAllocation },
+{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J", (void*)nAllocationCubeCreateFromBitmap },
-{"rsnAllocationCopyFromBitmap", "(JJJ)V", (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap", "(JJJ)V", (void*)nAllocationCopyToBitmap },
+{"rsnAllocationCopyFromBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyFromBitmap },
+{"rsnAllocationCopyToBitmap", "(JJLandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap },
{"rsnAllocationSyncAll", "(JJI)V", (void*)nAllocationSyncAll },
{"rsnAllocationSetupBufferQueue", "(JJI)V", (void*)nAllocationSetupBufferQueue },
diff --git a/services/Android.bp b/services/Android.bp
index 1e119363f545..5afed6c4fd19 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -113,7 +113,7 @@ droidstubs {
srcs: [":services-sources"],
installable: false,
// TODO: remove the --hide options below
- args: " --show-single-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
+ args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd8a3618733f..4515be8f4a9f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3029,25 +3029,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
// Finish setting up the full connection
- mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
- AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- // A network factory has connected. Send it all current NetworkRequests.
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.isListen()) continue;
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo nai = nri.mSatisfier;
- final int score;
- final int serial;
- if (nai != null) {
- score = nai.getCurrentScore();
- serial = nai.factorySerialNumber;
- } else {
- score = 0;
- serial = NetworkFactory.SerialNumber.NONE;
- }
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
- nri.request);
- }
+ NetworkFactoryInfo nfi = mNetworkFactoryInfos.get(msg.replyTo);
+ nfi.completeConnection();
+ sendAllRequestsToFactory(nfi);
} else {
loge("Error connecting NetworkFactory");
mNetworkFactoryInfos.remove(msg.obj);
@@ -3430,8 +3414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
- nri.request);
+ nfi.cancelRequest(nri.request);
}
} else {
// listens don't have a singular affectedNetwork. Check all networks to see
@@ -4927,16 +4910,33 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static class NetworkFactoryInfo {
public final String name;
public final Messenger messenger;
- public final AsyncChannel asyncChannel;
+ private final AsyncChannel mAsyncChannel;
public final int factorySerialNumber;
NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
int factorySerialNumber) {
this.name = name;
this.messenger = messenger;
- this.asyncChannel = asyncChannel;
+ this.mAsyncChannel = asyncChannel;
this.factorySerialNumber = factorySerialNumber;
}
+
+ void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
+ servingSerialNumber, request);
+ }
+
+ void cancelRequest(NetworkRequest request) {
+ mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request);
+ }
+
+ void connect(Context context, Handler handler) {
+ mAsyncChannel.connect(context, handler, messenger);
+ }
+
+ void completeConnection() {
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ }
}
private void ensureNetworkRequestHasType(NetworkRequest request) {
@@ -5325,7 +5325,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
- nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
+ nfi.connect(mContext, mTrackerHandler);
}
@Override
@@ -5961,8 +5961,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
- serial, networkRequest);
+ nfi.requestNetwork(networkRequest, score, serial);
+ }
+ }
+
+ /** Sends all current NetworkRequests to the specified factory. */
+ private void sendAllRequestsToFactory(NetworkFactoryInfo nfi) {
+ ensureRunningOnConnectivityServiceThread();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.request.isListen()) continue;
+ NetworkAgentInfo nai = nri.mSatisfier;
+ final int score;
+ final int serial;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkFactory.SerialNumber.NONE;
+ }
+ nfi.requestNetwork(nri.request, score, serial);
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c5f1923b0b98..0fc5340846f2 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -3192,6 +3192,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
ipw.decreaseIndent();
+ mRequestStatistics.history.dump(ipw);
+
ipw.println("Last Known Locations:");
ipw.increaseIndent();
for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1f736502ae42..05d83606b2d0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,10 +58,12 @@ import android.net.NetworkStack;
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
-import android.net.TetherConfigParcel;
import android.net.TetherStatsParcel;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.shared.NetdUtils;
+import android.net.shared.RouteUtils;
+import android.net.shared.RouteUtils.ModifyOperation;
import android.net.util.NetdService;
import android.os.BatteryStats;
import android.os.Binder;
@@ -898,48 +900,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void addRoute(int netId, RouteInfo route) {
- modifyRoute(MODIFY_OPERATION_ADD, netId, route);
+ NetworkStack.checkNetworkStackPermission(mContext);
+ RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route);
}
@Override
public void removeRoute(int netId, RouteInfo route) {
- modifyRoute(MODIFY_OPERATION_REMOVE, netId, route);
- }
-
- private void modifyRoute(boolean add, int netId, RouteInfo route) {
NetworkStack.checkNetworkStackPermission(mContext);
-
- final String ifName = route.getInterface();
- final String dst = route.getDestination().toString();
- final String nextHop;
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- nextHop = route.getGateway().getHostAddress();
- } else {
- nextHop = INetd.NEXTHOP_NONE;
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- nextHop = INetd.NEXTHOP_UNREACHABLE;
- break;
- case RouteInfo.RTN_THROW:
- nextHop = INetd.NEXTHOP_THROW;
- break;
- default:
- nextHop = INetd.NEXTHOP_NONE;
- break;
- }
- try {
- if (add) {
- mNetdService.networkAddRoute(netId, ifName, dst, nextHop);
- } else {
- mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop);
- }
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
+ RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route);
}
private ArrayList<String> readRouteList(String filename) {
@@ -1023,12 +991,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
NetworkStack.checkNetworkStackPermission(mContext);
- // an odd number of addrs will fail
try {
- final TetherConfigParcel config = new TetherConfigParcel();
- config.usingLegacyDnsProxy = usingLegacyDnsProxy;
- config.dhcpRanges = dhcpRange;
- mNetdService.tetherStartWithConfiguration(config);
+ NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1060,26 +1024,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
public void tetherInterface(String iface) {
NetworkStack.checkNetworkStackPermission(mContext);
try {
- mNetdService.tetherInterfaceAdd(iface);
+ final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress();
+ final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+ NetdUtils.tetherInterface(mNetdService, iface, dest);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
- List<RouteInfo> routes = new ArrayList<>();
- // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
- // suitable to use as a route destination.
- routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
- addInterfaceToLocalNetwork(iface, routes);
}
@Override
public void untetherInterface(String iface) {
NetworkStack.checkNetworkStackPermission(mContext);
try {
- mNetdService.tetherInterfaceRemove(iface);
+ NetdUtils.untetherInterface(mNetdService, iface);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
- } finally {
- removeInterfaceFromLocalNetwork(iface);
}
}
@@ -2122,16 +2081,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface);
-
- for (RouteInfo route : routes) {
- if (!route.isDefaultRoute()) {
- modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route);
- }
- }
-
- // IPv6 link local should be activated always.
- modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID,
- new RouteInfo(new IpPrefix("fe80::/64"), null, iface));
+ // modifyInterfaceInNetwork already check calling permission.
+ RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes);
}
@Override
@@ -2141,17 +2092,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
@Override
public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) {
- int failures = 0;
-
- for (RouteInfo route : routes) {
- try {
- modifyRoute(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, route);
- } catch (IllegalStateException e) {
- failures++;
- }
- }
-
- return failures;
+ NetworkStack.checkNetworkStackPermission(mContext);
+ return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes);
}
@Override
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index cfe56052118f..d20936c2d217 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -36,11 +36,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.TimestampedValue;
import android.provider.Settings;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TimeUtils;
-import android.util.TimestampedValue;
import com.android.internal.util.DumpUtils;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3d455ee1cf19..db542145a750 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.ACCESS_MTP;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
@@ -111,6 +112,7 @@ import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.provider.DeviceConfig;
+import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
import android.sysprop.VoldProperties;
@@ -367,6 +369,8 @@ class StorageManagerService extends IStorageManager.Stub
private volatile int mMediaStoreAuthorityAppId = -1;
+ private volatile int mDownloadsAuthorityAppId = -1;
+
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
private final Installer mInstaller;
@@ -1788,6 +1792,15 @@ class StorageManagerService extends IStorageManager.Stub
mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
+ provider = mPmInternal.resolveContentProvider(
+ Downloads.Impl.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.getUserId(UserHandle.USER_SYSTEM));
+
+ if (provider != null) {
+ mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
+ }
+
try {
mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
@@ -3881,6 +3894,19 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
+ if (mIsFuseEnabled && mDownloadsAuthorityAppId == UserHandle.getAppId(uid)) {
+ // DownloadManager can write in app-private directories on behalf of apps;
+ // give it write access to Android/
+ return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
+ }
+
+ final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
+ PERMISSION_GRANTED;
+ if (mIsFuseEnabled && hasMtp) {
+ // The process hosting the MTP server should be able to write in Android/
+ return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
+ }
+
// Determine if caller is holding runtime permission
final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 2091c2a0c694..9ffe89c61a44 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1059,8 +1059,8 @@ final class UiModeManagerService extends SystemService {
if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityTaskManager.getService().startActivityWithConfig(
- null, null, homeIntent, null, null, null, 0, 0,
- mConfiguration, null, UserHandle.USER_CURRENT);
+ null, getContext().getBasePackageName(), homeIntent, null, null, null,
+ 0, 0, mConfiguration, null, UserHandle.USER_CURRENT);
if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a4c44fabfba6..d7ad1c252401 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2934,33 +2934,37 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
ArraySet<Long> enabled = new ArraySet<>();
ArraySet<Long> disabled = new ArraySet<>();
- switch (toggleValue) {
- case "enable":
- enabled.add(changeId);
- pw.println("Enabled change " + changeId + " for " + packageName + ".");
- CompatibilityChangeConfig overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "disable":
- disabled.add(changeId);
- pw.println("Disabled change " + changeId + " for " + packageName + ".");
- overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- return 0;
- case "reset":
- if (platformCompat.clearOverride(changeId, packageName)) {
- pw.println("Reset change " + changeId + " for " + packageName
- + " to default value.");
- } else {
- pw.println("No override exists for changeId " + changeId + ".");
- }
- return 0;
- default:
- pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ try {
+ switch (toggleValue) {
+ case "enable":
+ enabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "disable":
+ disabled.add(changeId);
+ overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ return 0;
+ case "reset":
+ if (platformCompat.clearOverride(changeId, packageName)) {
+ pw.println("Reset change " + changeId + " for " + packageName
+ + " to default value.");
+ } else {
+ pw.println("No override exists for changeId " + changeId + ".");
+ }
+ return 0;
+ default:
+ pw.println("Invalid toggle value: '" + toggleValue + "'.");
+ }
+ } catch (SecurityException e) {
+ pw.println(e.getMessage());
}
return -1;
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a1e1f29016c2..76f54cdf91be 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1555,20 +1555,27 @@ public final class ProcessList {
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
-
+ int numGids = 3;
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER
+ || mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ numGids++;
+ }
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
if (ArrayUtils.isEmpty(permGids)) {
- gids = new int[3];
+ gids = new int[numGids];
} else {
- gids = new int[permGids.length + 3];
- System.arraycopy(permGids, 0, gids, 3, permGids.length);
+ gids = new int[permGids.length + numGids];
+ System.arraycopy(permGids, 0, gids, numGids, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+ if (numGids > 3) {
+ gids[3] = Process.SDCARD_RW_GID;
+ }
// Replace any invalid GIDs
if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index cf83dd630a29..f15d999e1006 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,8 +17,10 @@
package com.android.server.compat;
import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Environment;
+import android.os.RemoteException;
import android.text.TextUtils;
import android.util.LongArray;
import android.util.LongSparseArray;
@@ -26,8 +28,11 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.config.XmlParser;
@@ -54,22 +59,14 @@ final class CompatConfig {
private static final String TAG = "CompatConfig";
- private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
- Environment.buildPath(
- Environment.getRootDirectory(), "etc", "compatconfig"));
-
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
- @VisibleForTesting
- CompatConfig() {
- }
+ private IOverrideValidator mOverrideValidator;
- /**
- * @return The static instance of this class to be used within the system server.
- */
- static CompatConfig get() {
- return sInstance;
+ @VisibleForTesting
+ CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
}
/**
@@ -159,8 +156,12 @@ final class CompatConfig {
* @param enabled If the change should be enabled or disabled.
* @return {@code true} if the change existed before adding the override.
*/
- boolean addOverride(long changeId, String packageName, boolean enabled) {
+ boolean addOverride(long changeId, String packageName, boolean enabled)
+ throws RemoteException, SecurityException {
boolean alreadyKnown = true;
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c == null) {
@@ -186,6 +187,20 @@ final class CompatConfig {
}
/**
+ * Returns the minimum sdk version for which this change should be enabled (or 0 if it is not
+ * target sdk gated).
+ */
+ int minTargetSdkForChangeId(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ return 0;
+ }
+ return c.getEnableAfterTargetSdk();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
* restores the default behaviour for the given change and app, once any app processes have been
* restarted.
@@ -194,34 +209,44 @@ final class CompatConfig {
* @param packageName The app package name that was overridden.
* @return {@code true} if an override existed;
*/
- boolean removeOverride(long changeId, String packageName) {
+ boolean removeOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c != null) {
- overrideExists = true;
- c.removePackageOverride(packageName);
+ try {
+ if (c != null) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
+ overrideExists = true;
+ c.removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
}
}
return overrideExists;
}
/**
- * Overrides the enabled state for a given change and app. This method is intended to be used
- * *only* for debugging purposes.
+ * Overrides the enabled state for a given change and app.
*
* <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
*
* @param overrides list of overrides to default changes config.
* @param packageName app for which the overrides will be applied.
*/
- void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
+ void addOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
synchronized (mChanges) {
for (Long changeId : overrides.enabledChanges()) {
addOverride(changeId, packageName, true);
}
for (Long changeId : overrides.disabledChanges()) {
addOverride(changeId, packageName, false);
+
}
}
}
@@ -235,10 +260,22 @@ final class CompatConfig {
*
* @param packageName The package for which the overrides should be purged.
*/
- void removePackageOverrides(String packageName) {
+ void removePackageOverrides(String packageName) throws RemoteException, SecurityException {
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
- mChanges.valueAt(i).removePackageOverride(packageName);
+ try {
+ CompatChange change = mChanges.valueAt(i);
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ allowedState.enforce(change.getId(), packageName);
+ if (change != null) {
+ mChanges.valueAt(i).removePackageOverride(packageName);
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
+ }
}
}
}
@@ -326,17 +363,23 @@ final class CompatConfig {
}
}
- CompatConfig initConfigFromLib(File libraryDir) {
+ static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ CompatConfig config = new CompatConfig(androidBuildClassifier, context);
+ config.initConfigFromLib(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "compatconfig"));
+ return config;
+ }
+
+ void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.e(TAG, "No directory " + libraryDir + ", skipping");
- return this;
+ return;
}
for (File f : libraryDir.listFiles()) {
Slog.d(TAG, "Found a config file: " + f.getPath());
//TODO(b/138222363): Handle duplicate ids across config files.
readConfig(f);
}
- return this;
}
private void readConfig(File configFile) {
@@ -350,4 +393,7 @@ final class CompatConfig {
}
}
+ IOverrideValidator getOverrideValidator() {
+ return mOverrideValidator;
+ }
}
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
new file mode 100644
index 000000000000..dfc00806992b
--- /dev/null
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+/**
+ * Implementation of the policy for allowing compat change overrides.
+ */
+public class OverrideValidatorImpl extends IOverrideValidator.Stub {
+
+ private AndroidBuildClassifier mAndroidBuildClassifier;
+ private Context mContext;
+ private CompatConfig mCompatConfig;
+
+ @VisibleForTesting
+ OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier,
+ Context context, CompatConfig config) {
+ mAndroidBuildClassifier = androidBuildClassifier;
+ mContext = context;
+ mCompatConfig = config;
+ }
+
+ @Override
+ public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
+ boolean debuggableBuild = false;
+ boolean finalBuild = false;
+
+ debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+ finalBuild = mAndroidBuildClassifier.isFinalBuild();
+
+ // Allow any override for userdebug or eng builds.
+ if (debuggableBuild) {
+ return new OverrideAllowedState(ALLOWED, -1, -1);
+ }
+ PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager == null) {
+ throw new IllegalStateException("No PackageManager!");
+ }
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1);
+ }
+ int appTargetSdk = applicationInfo.targetSdkVersion;
+ // Only allow overriding debuggable apps.
+ if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1);
+ }
+ int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+ // Do not allow overriding non-target sdk gated changes on user builds
+ if (minTargetSdk == -1) {
+ return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
+ }
+ // Allow overriding any change for debuggable apps on non-final builds.
+ if (!finalBuild) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ // Only allow to opt-in for a targetSdk gated change.
+ if (applicationInfo.targetSdkVersion < minTargetSdk) {
+ return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
+ }
+ return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
+ }
+}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6ec4b9fbdb93..bb8b12e86e16 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -27,9 +27,12 @@ import android.os.UserHandle;
import android.util.Slog;
import android.util.StatsLog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.ChangeReporter;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
@@ -46,11 +49,21 @@ public class PlatformCompat extends IPlatformCompat.Stub {
private final Context mContext;
private final ChangeReporter mChangeReporter;
+ private final CompatConfig mCompatConfig;
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+ }
+
+ @VisibleForTesting
+ PlatformCompat(Context context, CompatConfig compatConfig) {
+ mContext = context;
+ mChangeReporter = new ChangeReporter(
+ StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ mCompatConfig = compatConfig;
}
@Override
@@ -75,7 +88,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
+ if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
return true;
@@ -122,57 +135,59 @@ public class PlatformCompat extends IPlatformCompat.Stub {
* otherwise.
*/
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
- return CompatConfig.get().registerListener(changeId, listener);
+ return mCompatConfig.registerListener(changeId, listener);
}
@Override
- public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@Override
- public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
- CompatConfig.get().addOverrides(overrides, packageName);
+ public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.addOverrides(overrides, packageName);
}
@Override
- public void clearOverrides(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@Override
- public void clearOverridesForTest(String packageName) {
- CompatConfig config = CompatConfig.get();
- config.removePackageOverrides(packageName);
+ public void clearOverridesForTest(String packageName)
+ throws RemoteException, SecurityException {
+ mCompatConfig.removePackageOverrides(packageName);
}
@Override
- public boolean clearOverride(long changeId, String packageName) {
- boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
+ public boolean clearOverride(long changeId, String packageName)
+ throws RemoteException, SecurityException {
+ boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
}
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- return CompatConfig.get().getAppConfig(appInfo);
+ return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
- return CompatConfig.get().dumpChanges();
+ return mCompatConfig.dumpChanges();
}
/**
* Check whether the change is known to the compat config.
- * @param changeId
+ *
* @return {@code true} if the change is known.
*/
public boolean isKnownChangeId(long changeId) {
- return CompatConfig.get().isKnownChangeId(changeId);
+ return mCompatConfig.isKnownChangeId(changeId);
}
@@ -182,11 +197,11 @@ public class PlatformCompat extends IPlatformCompat.Stub {
*
* @param appInfo The app in question
* @return A sorted long array of change IDs. We use a primitive array to minimize memory
- * footprint: Every app process will store this array statically so we aim to reduce
- * overhead as much as possible.
+ * footprint: Every app process will store this array statically so we aim to reduce
+ * overhead as much as possible.
*/
public long[] getDisabledChanges(ApplicationInfo appInfo) {
- return CompatConfig.get().getDisabledChanges(appInfo);
+ return mCompatConfig.getDisabledChanges(appInfo);
}
/**
@@ -196,18 +211,24 @@ public class PlatformCompat extends IPlatformCompat.Stub {
* @return The change ID, or {@code -1} if no change with that name exists.
*/
public long lookupChangeId(String name) {
- return CompatConfig.get().lookupChangeId(name);
+ return mCompatConfig.lookupChangeId(name);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
- CompatConfig.get().dumpConfig(pw);
+ mCompatConfig.dumpConfig(pw);
+ }
+
+ @Override
+ public IOverrideValidator getOverrideValidator() {
+ return mCompatConfig.getOverrideValidator();
}
/**
* Clears information stored about events reported on behalf of an app.
* To be called once upon app start or end. A second call would be a no-op.
+ *
* @param appInfo the app to reset
*/
public void resetReporting(ApplicationInfo appInfo) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e39d6d5389e3..d7ae5b5c91bd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1305,13 +1305,21 @@ public final class DisplayManagerService extends SystemService {
}
private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) {
- final IBinder token = getDisplayToken(displayId);
- if (token == null) {
- return null;
+ synchronized (mSyncRoot) {
+ final IBinder token = getDisplayToken(displayId);
+ if (token == null) {
+ return null;
+ }
+ final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId);
+ if (logicalDisplay == null) {
+ return null;
+ }
+
+ final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
+ return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(),
+ displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(),
+ false /* useIdentityTransform */, 0 /* rotation */);
}
- return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(
- token, new Rect(), 0 /* width */, 0 /* height */,
- false /* useIdentityTransform */, 0 /* rotation */);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index ad728c18dd59..8498dcb32eb1 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -237,15 +237,15 @@ public class DisplayModeDirector {
lowestConsideredPriority++;
}
- int defaultModeId = defaultMode.getModeId();
+ int baseModeId = defaultMode.getModeId();
if (availableModes.length > 0) {
- defaultModeId = availableModes[0];
+ baseModeId = availableModes[0];
}
// filterModes function is going to filter the modes based on the voting system. If
// the application requests a given mode with preferredModeId function, it will be
- // stored as defaultModeId.
+ // stored as baseModeId.
return new DesiredDisplayModeSpecs(
- defaultModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
+ baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
}
}
@@ -526,7 +526,7 @@ public class DisplayModeDirector {
}
/**
- * Information about the desired display mode to be set by the system. Includes the default
+ * Information about the desired display mode to be set by the system. Includes the base
* mode ID and refresh rate range.
*
* We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
@@ -535,10 +535,10 @@ public class DisplayModeDirector {
*/
public static final class DesiredDisplayModeSpecs {
/**
- * Default mode ID. This is what system defaults to for all other settings, or
+ * Base mode ID. This is what system defaults to for all other settings, or
* if the refresh rate range is not available.
*/
- public int defaultModeId;
+ public int baseModeId;
/**
* The refresh rate range.
*/
@@ -548,9 +548,8 @@ public class DisplayModeDirector {
refreshRateRange = new RefreshRateRange();
}
- public DesiredDisplayModeSpecs(
- int defaultModeId, @NonNull RefreshRateRange refreshRateRange) {
- this.defaultModeId = defaultModeId;
+ public DesiredDisplayModeSpecs(int baseModeId, @NonNull RefreshRateRange refreshRateRange) {
+ this.baseModeId = baseModeId;
this.refreshRateRange = refreshRateRange;
}
@@ -559,7 +558,7 @@ public class DisplayModeDirector {
*/
@Override
public String toString() {
- return String.format("defaultModeId=%d min=%.0f max=%.0f", defaultModeId,
+ return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId,
refreshRateRange.min, refreshRateRange.max);
}
/**
@@ -577,7 +576,7 @@ public class DisplayModeDirector {
DesiredDisplayModeSpecs desiredDisplayModeSpecs = (DesiredDisplayModeSpecs) other;
- if (defaultModeId != desiredDisplayModeSpecs.defaultModeId) {
+ if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
return false;
}
if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) {
@@ -588,14 +587,14 @@ public class DisplayModeDirector {
@Override
public int hashCode() {
- return Objects.hash(defaultModeId, refreshRateRange);
+ return Objects.hash(baseModeId, refreshRateRange);
}
/**
* Copy values from the other object.
*/
public void copyFrom(DesiredDisplayModeSpecs other) {
- defaultModeId = other.defaultModeId;
+ baseModeId = other.baseModeId;
refreshRateRange.min = other.refreshRateRange.min;
refreshRateRange.max = other.refreshRateRange.max;
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index cf94d4695497..fb8a4193286b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -272,14 +272,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
- if (mDisplayModeSpecs.defaultModeId != 0) {
- int activeDefaultMode =
+ if (mDisplayModeSpecs.baseModeId != 0) {
+ int activeBaseMode =
findMatchingModeIdLocked(physicalDisplayConfigSpecs.defaultConfig);
// If we can't map the defaultConfig index to a mode, then the physical display
// configs must have changed, and the code below for handling changes to the
// list of available modes will take care of updating display config specs.
- if (activeDefaultMode != 0) {
- if (mDisplayModeSpecs.defaultModeId != activeDefaultMode
+ if (activeBaseMode != 0) {
+ if (mDisplayModeSpecs.baseModeId != activeBaseMode
|| mDisplayModeSpecs.refreshRateRange.min
!= physicalDisplayConfigSpecs.minRefreshRate
|| mDisplayModeSpecs.refreshRateRange.max
@@ -312,14 +312,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mDefaultModeId = activeRecord.mMode.getModeId();
}
- // Determine whether the display mode specs' default mode is still there.
- if (mSupportedModes.indexOfKey(mDisplayModeSpecs.defaultModeId) < 0) {
- if (mDisplayModeSpecs.defaultModeId != 0) {
+ // Determine whether the display mode specs' base mode is still there.
+ if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) {
+ if (mDisplayModeSpecs.baseModeId != 0) {
Slog.w(TAG,
- "DisplayModeSpecs default mode no longer available, using currently"
- + " active mode as default.");
+ "DisplayModeSpecs base mode no longer available, using currently"
+ + " active mode.");
}
- mDisplayModeSpecs.defaultModeId = activeRecord.mMode.getModeId();
+ mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId();
mDisplayModeSpecsInvalid = true;
}
@@ -648,13 +648,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public void setDesiredDisplayModeSpecsLocked(
DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
- if (displayModeSpecs.defaultModeId == 0) {
+ if (displayModeSpecs.baseModeId == 0) {
// Bail if the caller is requesting a null mode. We'll get called again shortly with
// a valid mode.
return;
}
- int defaultPhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.defaultModeId);
- if (defaultPhysIndex < 0) {
+ int basePhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.baseModeId);
+ if (basePhysIndex < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -662,8 +662,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// mode. This should only happen in extremely rare cases. A followup call will
// contain a valid mode id.
Slog.w(TAG,
- "Ignoring request for invalid default mode id "
- + displayModeSpecs.defaultModeId);
+ "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId);
updateDeviceInfoLocked();
return;
}
@@ -673,7 +672,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
- new SurfaceControl.DesiredDisplayConfigSpecs(defaultPhysIndex,
+ new SurfaceControl.DesiredDisplayConfigSpecs(basePhysIndex,
mDisplayModeSpecs.refreshRateRange.min,
mDisplayModeSpecs.refreshRateRange.max)));
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index b6255d15795e..c8e5f6c8f53b 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -317,7 +317,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
@Override
public void setDesiredDisplayModeSpecsLocked(
DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {
- final int id = displayModeSpecs.defaultModeId;
+ final int id = displayModeSpecs.baseModeId;
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
index f90fab4666d6..31d4816e5d66 100644
--- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java
+++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.integrity.parser.RuleBinaryParser;
+import com.android.server.integrity.parser.RuleIndexRange;
import com.android.server.integrity.parser.RuleIndexingController;
import com.android.server.integrity.parser.RuleMetadataParser;
import com.android.server.integrity.parser.RuleParseException;
@@ -152,7 +153,7 @@ public class IntegrityFileManager {
throws IOException, RuleParseException {
synchronized (RULES_LOCK) {
// Try to identify indexes from the index file.
- List<List<Integer>> ruleReadingIndexes =
+ List<RuleIndexRange> ruleReadingIndexes =
mRuleIndexingController.identifyRulesToEvaluate(appInstallMetadata);
// Read the rules based on the index information.
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
new file mode 100644
index 000000000000..8c8450e5fdc4
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexRange.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import android.annotation.Nullable;
+
+/**
+ * A wrapper class to represent an indexing range that is identified by the {@link
+ * RuleIndexingController}.
+ */
+public class RuleIndexRange {
+ private static int sStartIndex;
+ private static int sEndIndex;
+
+ /** Constructor with start and end indexes. */
+ public RuleIndexRange(int startIndex, int endIndex) {
+ this.sStartIndex = startIndex;
+ this.sEndIndex = endIndex;
+ }
+
+ /** Returns the startIndex. */
+ public int getStartIndex() {
+ return sStartIndex;
+ }
+
+ /** Returns the end index. */
+ public int getEndIndex() {
+ return sEndIndex;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ return sStartIndex == ((RuleIndexRange) object).getStartIndex()
+ && sEndIndex == ((RuleIndexRange) object).getEndIndex();
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index b642fa64baaf..c9713220d6e8 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -17,6 +17,7 @@
package com.android.server.integrity.parser;
import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;
@@ -24,25 +25,27 @@ import android.content.integrity.AppInstallMetadata;
import com.android.server.integrity.model.BitInputStream;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
-import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
/** Helper class to identify the necessary indexes that needs to be read. */
public class RuleIndexingController {
- private static TreeMap<String, Integer> sPackageNameBasedIndexes;
- private static TreeMap<String, Integer> sAppCertificateBasedIndexes;
- private static TreeMap<String, Integer> sUnindexedRuleIndexes;
+ private static LinkedHashMap<String, Integer> sPackageNameBasedIndexes;
+ private static LinkedHashMap<String, Integer> sAppCertificateBasedIndexes;
+ private static LinkedHashMap<String, Integer> sUnindexedRuleIndexes;
/**
* Provide the indexing file to read and the object will be constructed by reading and
* identifying the indexes.
*/
- public RuleIndexingController(FileInputStream fileInputStream) throws IOException {
- BitInputStream bitInputStream = new BitInputStream(fileInputStream);
+ public RuleIndexingController(InputStream inputStream) throws IOException {
+ BitInputStream bitInputStream = new BitInputStream(inputStream);
sPackageNameBasedIndexes = getNextIndexGroup(bitInputStream);
sAppCertificateBasedIndexes = getNextIndexGroup(bitInputStream);
sUnindexedRuleIndexes = getNextIndexGroup(bitInputStream);
@@ -52,24 +55,57 @@ public class RuleIndexingController {
* Returns a list of integers with the starting and ending bytes of the rules that needs to be
* read and evaluated.
*/
- public List<List<Integer>> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
- // TODO(b/145493956): Identify and return the indexes that needs to be read.
- return new ArrayList<>();
+ public List<RuleIndexRange> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
+ ArrayList<RuleIndexRange> indexRanges = new ArrayList();
+
+ // Add the range for package name indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sPackageNameBasedIndexes, appInstallMetadata.getPackageName()));
+
+ // Add the range for app certificate indexes rules.
+ indexRanges.add(
+ searchIndexingKeysRangeContainingKey(
+ sAppCertificateBasedIndexes, appInstallMetadata.getAppCertificate()));
+
+ // Add the range for unindexed rules.
+ indexRanges.add(
+ new RuleIndexRange(
+ sUnindexedRuleIndexes.get(START_INDEXING_KEY),
+ sUnindexedRuleIndexes.get(END_INDEXING_KEY)));
+
+ return indexRanges;
}
- private TreeMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
+ private LinkedHashMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
throws IOException {
- TreeMap<String, Integer> keyToIndexMap = new TreeMap<>();
+ LinkedHashMap<String, Integer> keyToIndexMap = new LinkedHashMap<>();
while (bitInputStream.hasNext()) {
String key = getStringValue(bitInputStream);
int value = getIntValue(bitInputStream);
keyToIndexMap.put(key, value);
- if (key == END_INDEXING_KEY) {
+ if (key.matches(END_INDEXING_KEY)) {
break;
}
}
return keyToIndexMap;
}
+
+ private RuleIndexRange searchIndexingKeysRangeContainingKey(
+ LinkedHashMap<String, Integer> indexMap, String searchedKey) {
+ TreeSet<String> keyTreeSet =
+ indexMap.keySet().stream()
+ .filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
+ END_INDEXING_KEY))
+ .collect(Collectors.toCollection(TreeSet::new));
+
+ String minIndex = keyTreeSet.floor(searchedKey);
+ String maxIndex = keyTreeSet.ceiling(searchedKey);
+
+ return new RuleIndexRange(
+ indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
+ indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
+ }
}
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7ccb26da64b..45c833498ac7 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -1,8 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.location;
import android.os.SystemClock;
import android.util.Log;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -17,6 +38,8 @@ public class LocationRequestStatistics {
public final HashMap<PackageProviderKey, PackageStatistics> statistics
= new HashMap<PackageProviderKey, PackageStatistics>();
+ public final RequestSummaryLimitedHistory history = new RequestSummaryLimitedHistory();
+
/**
* Signals that a package has started requesting locations.
*
@@ -34,6 +57,7 @@ public class LocationRequestStatistics {
}
stats.startRequesting(intervalMs);
stats.updateForeground(isForeground);
+ history.addRequest(packageName, providerName, intervalMs);
}
/**
@@ -48,6 +72,7 @@ public class LocationRequestStatistics {
if (stats != null) {
stats.stopRequesting();
}
+ history.removeRequest(packageName, providerName);
}
/**
@@ -77,7 +102,7 @@ public class LocationRequestStatistics {
*/
public final String providerName;
- public PackageProviderKey(String packageName, String providerName) {
+ PackageProviderKey(String packageName, String providerName) {
this.packageName = packageName;
this.providerName = providerName;
}
@@ -100,6 +125,104 @@ public class LocationRequestStatistics {
}
/**
+ * A data structure to hold past requests
+ */
+ public static class RequestSummaryLimitedHistory {
+ @VisibleForTesting
+ static final int MAX_SIZE = 100;
+
+ final ArrayList<RequestSummary> mList = new ArrayList<>(MAX_SIZE);
+
+ /**
+ * Append an added location request to the history
+ */
+ @VisibleForTesting
+ void addRequest(String packageName, String providerName, long intervalMs) {
+ addRequestSummary(new RequestSummary(packageName, providerName, intervalMs));
+ }
+
+ /**
+ * Append a removed location request to the history
+ */
+ @VisibleForTesting
+ void removeRequest(String packageName, String providerName) {
+ addRequestSummary(new RequestSummary(
+ packageName, providerName, RequestSummary.REQUEST_ENDED_INTERVAL));
+ }
+
+ private void addRequestSummary(RequestSummary summary) {
+ while (mList.size() >= MAX_SIZE) {
+ mList.remove(0);
+ }
+ mList.add(summary);
+ }
+
+ /**
+ * Dump history to a printwriter (for dumpsys location)
+ */
+ public void dump(IndentingPrintWriter ipw) {
+ long systemElapsedOffsetMillis = System.currentTimeMillis()
+ - SystemClock.elapsedRealtime();
+
+ ipw.println("Last Several Location Requests:");
+ ipw.increaseIndent();
+
+ for (RequestSummary requestSummary : mList) {
+ requestSummary.dump(ipw, systemElapsedOffsetMillis);
+ }
+
+ ipw.decreaseIndent();
+ }
+ }
+
+ /**
+ * A data structure to hold a single request
+ */
+ static class RequestSummary {
+ /**
+ * Name of package requesting location.
+ */
+ private final String mPackageName;
+ /**
+ * Name of provider being requested (e.g. "gps").
+ */
+ private final String mProviderName;
+ /**
+ * Interval Requested, or REQUEST_ENDED_INTERVAL indicating request has ended
+ */
+ private final long mIntervalMillis;
+ /**
+ * Elapsed time of request
+ */
+ private final long mElapsedRealtimeMillis;
+
+ /**
+ * Placeholder for requested ending (other values indicate request started/changed)
+ */
+ static final long REQUEST_ENDED_INTERVAL = -1;
+
+ RequestSummary(String packageName, String providerName, long intervalMillis) {
+ this.mPackageName = packageName;
+ this.mProviderName = providerName;
+ this.mIntervalMillis = intervalMillis;
+ this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
+ }
+
+ void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
+ StringBuilder s = new StringBuilder();
+ long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
+ s.append("At ").append(TimeUtils.formatForLogging(systemTimeMillis)).append(": ")
+ .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
+ .append(String.format("%7s", mProviderName)).append(" request from ")
+ .append(mPackageName);
+ if (mIntervalMillis != REQUEST_ENDED_INTERVAL) {
+ s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds");
+ }
+ ipw.println(s);
+ }
+ }
+
+ /**
* Usage statistics for a package/provider pair.
*/
public static class PackageStatistics {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 115155ce24b5..9ca302edd204 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
-import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.RouteSessionInfo;
@@ -47,16 +46,16 @@ abstract class MediaRoute2Provider {
}
public abstract void requestCreateSession(String packageName, String routeId,
- String controlCategory, long requestId);
+ String routeType, long requestId);
public abstract void releaseSession(int sessionId);
- public abstract void selectRoute(int sessionId, MediaRoute2Info route);
- public abstract void deselectRoute(int sessionId, MediaRoute2Info route);
- public abstract void transferToRoute(int sessionId, MediaRoute2Info route);
+ public abstract void selectRoute(int sessionId, String routeId);
+ public abstract void deselectRoute(int sessionId, String routeId);
+ public abstract void transferToRoute(int sessionId, String routeId);
- public abstract void sendControlRequest(MediaRoute2Info route, Intent request);
- public abstract void requestSetVolume(MediaRoute2Info route, int volume);
- public abstract void requestUpdateVolume(MediaRoute2Info route, int delta);
+ public abstract void sendControlRequest(String routeId, Intent request);
+ public abstract void requestSetVolume(String routeId, int volume);
+ public abstract void requestUpdateVolume(String routeId, int delta);
@NonNull
public String getUniqueId() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index f8d8f9fd5fbd..5cc2b16e073a 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -24,7 +24,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.media.IMediaRoute2Provider;
import android.media.IMediaRoute2ProviderClient;
-import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
import android.media.RouteSessionInfo;
@@ -77,10 +76,10 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
@Override
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
if (mConnectionReady) {
- mActiveConnection.requestCreateSession(packageName, routeId, controlCategory,
+ mActiveConnection.requestCreateSession(packageName, routeId, routeType,
requestId);
updateBinding();
}
@@ -95,46 +94,46 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
}
@Override
- public void selectRoute(int sessionId, MediaRoute2Info route) {
+ public void selectRoute(int sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(sessionId, route.getId());
+ mActiveConnection.selectRoute(sessionId, routeId);
}
}
@Override
- public void deselectRoute(int sessionId, MediaRoute2Info route) {
+ public void deselectRoute(int sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.deselectRoute(sessionId, route.getId());
+ mActiveConnection.deselectRoute(sessionId, routeId);
}
}
@Override
- public void transferToRoute(int sessionId, MediaRoute2Info route) {
+ public void transferToRoute(int sessionId, String routeId) {
if (mConnectionReady) {
- mActiveConnection.transferToRoute(sessionId, route.getId());
+ mActiveConnection.transferToRoute(sessionId, routeId);
}
}
@Override
- public void sendControlRequest(MediaRoute2Info route, Intent request) {
+ public void sendControlRequest(String routeId, Intent request) {
if (mConnectionReady) {
- mActiveConnection.sendControlRequest(route.getId(), request);
+ mActiveConnection.sendControlRequest(routeId, request);
updateBinding();
}
}
@Override
- public void requestSetVolume(MediaRoute2Info route, int volume) {
+ public void requestSetVolume(String routeId, int volume) {
if (mConnectionReady) {
- mActiveConnection.requestSetVolume(route.getId(), volume);
+ mActiveConnection.requestSetVolume(routeId, volume);
updateBinding();
}
}
@Override
- public void requestUpdateVolume(MediaRoute2Info route, int delta) {
+ public void requestUpdateVolume(String routeId, int delta) {
if (mConnectionReady) {
- mActiveConnection.requestUpdateVolume(route.getId(), delta);
+ mActiveConnection.requestUpdateVolume(routeId, delta);
updateBinding();
}
}
@@ -346,11 +345,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
mClient.dispose();
}
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
try {
mProvider.requestCreateSession(packageName, routeId,
- controlCategory, requestId);
+ routeType, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to create a session.", ex);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 562a7200fb38..b48243279d9e 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -28,6 +28,7 @@ import android.media.IMediaRouter2Client;
import android.media.IMediaRouter2Manager;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -174,18 +175,18 @@ class MediaRouter2ServiceImpl {
}
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String controlCategory, int requestId) {
+ String routeType, int requestId) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(controlCategory)) {
- throw new IllegalArgumentException("controlCategory must not be empty");
+ if (TextUtils.isEmpty(routeType)) {
+ throw new IllegalArgumentException("routeType must not be empty");
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestCreateSessionLocked(client, route, controlCategory, requestId);
+ requestCreateSessionLocked(client, route, routeType, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -267,16 +268,16 @@ class MediaRouter2ServiceImpl {
}
}
- public void setControlCategories(@NonNull IMediaRouter2Client client,
- @NonNull List<String> categories) {
+ public void setDiscoveryRequest2(@NonNull IMediaRouter2Client client,
+ @NonNull RouteDiscoveryRequest request) {
Objects.requireNonNull(client, "client must not be null");
- Objects.requireNonNull(categories, "categories must not be null");
+ Objects.requireNonNull(request, "request must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
Client2Record clientRecord = mAllClientRecords.get(client.asBinder());
- setControlCategoriesLocked(clientRecord, categories);
+ setDiscoveryRequestLocked(clientRecord, request);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -434,7 +435,7 @@ class MediaRouter2ServiceImpl {
}
private void requestCreateSessionLocked(@NonNull IMediaRouter2Client client,
- @NonNull MediaRoute2Info route, @NonNull String controlCategory, long requestId) {
+ @NonNull MediaRoute2Info route, @NonNull String routeType, long requestId) {
final IBinder binder = client.asBinder();
final Client2Record clientRecord = mAllClientRecords.get(binder);
@@ -447,7 +448,7 @@ class MediaRouter2ServiceImpl {
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
clientRecord.mUserRecord.mHandler,
- clientRecord, route, controlCategory, requestId));
+ clientRecord, route, routeType, requestId));
}
}
@@ -502,13 +503,14 @@ class MediaRouter2ServiceImpl {
}
}
- private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) {
+ private void setDiscoveryRequestLocked(Client2Record clientRecord,
+ RouteDiscoveryRequest discoveryRequest) {
if (clientRecord != null) {
- if (clientRecord.mControlCategories.equals(categories)) {
+ if (clientRecord.mDiscoveryRequest.equals(discoveryRequest)) {
return;
}
- clientRecord.mControlCategories = categories;
+ clientRecord.mDiscoveryRequest = discoveryRequest;
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::updateClientUsage,
clientRecord.mUserRecord.mHandler, clientRecord));
@@ -607,7 +609,7 @@ class MediaRouter2ServiceImpl {
if (clientRecord != null && managerRecord.mTrusted) {
//TODO: select category properly
requestCreateSessionLocked(clientRecord.mClient, route,
- route.getSupportedCategories().get(0), uniqueRequestId);
+ route.getRouteTypes().get(0), uniqueRequestId);
}
}
}
@@ -725,7 +727,7 @@ class MediaRouter2ServiceImpl {
public final boolean mTrusted;
public final int mClientId;
- public List<String> mControlCategories;
+ public RouteDiscoveryRequest mDiscoveryRequest;
public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
@@ -735,7 +737,7 @@ class MediaRouter2ServiceImpl {
mUserRecord = userRecord;
mPackageName = packageName;
mSelectRouteSequenceNumbers = new ArrayList<>();
- mControlCategories = Collections.emptyList();
+ mDiscoveryRequest = RouteDiscoveryRequest.EMPTY;
mClient = client;
mUid = uid;
mPid = pid;
@@ -961,7 +963,7 @@ class MediaRouter2ServiceImpl {
}
private void requestCreateSessionOnHandler(Client2Record clientRecord,
- MediaRoute2Info route, String controlCategory, long requestId) {
+ MediaRoute2Info route, String routeType, long requestId) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
@@ -971,20 +973,20 @@ class MediaRouter2ServiceImpl {
return;
}
- if (!route.getSupportedCategories().contains(controlCategory)) {
+ if (!route.getRouteTypes().contains(routeType)) {
Slog.w(TAG, "Ignoring session creation request since the given route=" + route
- + " doesn't support the given category=" + controlCategory);
+ + " doesn't support the given type=" + routeType);
notifySessionCreationFailed(clientRecord, toClientRequestId(requestId));
return;
}
// TODO: Apply timeout for each request (How many seconds should we wait?)
SessionCreationRequest request = new SessionCreationRequest(
- clientRecord, route, controlCategory, requestId);
+ clientRecord, route, routeType, requestId);
mSessionCreationRequests.add(request);
- provider.requestCreateSession(clientRecord.mPackageName, route.getId(),
- controlCategory, requestId);
+ provider.requestCreateSession(clientRecord.mPackageName, route.getOriginalId(),
+ routeType, requestId);
}
private void selectRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1000,7 +1002,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.selectRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.selectRoute(RouteSessionInfo.getSessionId(uniqueSessionId),
+ route.getOriginalId());
}
private void deselectRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1016,7 +1019,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.deselectRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.deselectRoute(RouteSessionInfo.getSessionId(uniqueSessionId),
+ route.getOriginalId());
}
private void transferToRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1032,7 +1036,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.transferToRoute(RouteSessionInfo.getSessionId(uniqueSessionId), route);
+ provider.transferToRoute(RouteSessionInfo.getSessionId(uniqueSessionId),
+ route.getOriginalId());
}
private boolean checkArgumentsForSessionControl(@NonNull Client2Record clientRecord,
@@ -1141,12 +1146,12 @@ class MediaRouter2ServiceImpl {
}
String originalRouteId = matchingRequest.mRoute.getId();
- String originalCategory = matchingRequest.mControlCategory;
+ String originalCategory = matchingRequest.mRouteType;
Client2Record client2Record = matchingRequest.mClientRecord;
if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)
|| !TextUtils.equals(originalCategory,
- sessionInfo.getControlCategory())) {
+ sessionInfo.getRouteType())) {
Slog.w(TAG, "Created session doesn't match the original request."
+ " originalRouteId=" + originalRouteId
+ ", originalCategory=" + originalCategory + ", requestId=" + requestId
@@ -1239,21 +1244,21 @@ class MediaRouter2ServiceImpl {
private void sendControlRequest(MediaRoute2Info route, Intent request) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.sendControlRequest(route, request);
+ provider.sendControlRequest(route.getOriginalId(), request);
}
}
private void requestSetVolume(MediaRoute2Info route, int volume) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.requestSetVolume(route, volume);
+ provider.requestSetVolume(route.getOriginalId(), volume);
}
}
private void requestUpdateVolume(MediaRoute2Info route, int delta) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.requestUpdateVolume(route, delta);
+ provider.requestUpdateVolume(route.getOriginalId(), delta);
}
}
@@ -1401,8 +1406,8 @@ class MediaRouter2ServiceImpl {
try {
manager.notifyRouteSelected(clientRecord.mPackageName,
clientRecord.mSelectedRoute);
- manager.notifyControlCategoriesChanged(clientRecord.mPackageName,
- clientRecord.mControlCategories);
+ manager.notifyRouteTypesChanged(clientRecord.mPackageName,
+ clientRecord.mDiscoveryRequest.getRouteTypes());
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to update client usage. Manager probably died.", ex);
}
@@ -1421,15 +1426,15 @@ class MediaRouter2ServiceImpl {
final class SessionCreationRequest {
public final Client2Record mClientRecord;
public final MediaRoute2Info mRoute;
- public final String mControlCategory;
+ public final String mRouteType;
public final long mRequestId;
SessionCreationRequest(@NonNull Client2Record clientRecord,
@NonNull MediaRoute2Info route,
- @NonNull String controlCategory, long requestId) {
+ @NonNull String routeType, long requestId) {
mClientRecord = clientRecord;
mRoute = route;
- mControlCategory = controlCategory;
+ mRouteType = routeType;
mRequestId = requestId;
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index d77f43b4435d..c76555cf15cf 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -39,6 +39,7 @@ import android.media.MediaRouter;
import android.media.MediaRouterClientState;
import android.media.RemoteDisplayState;
import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.media.RouteDiscoveryRequest;
import android.media.RouteSessionInfo;
import android.os.Binder;
import android.os.Handler;
@@ -459,8 +460,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String controlCategory, int requestId) {
- mService2.requestCreateSession(client, route, controlCategory, requestId);
+ String routeType, int requestId) {
+ mService2.requestCreateSession(client, route, routeType, requestId);
}
// Binder call
@@ -519,8 +520,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}
// Binder call
@Override
- public void setControlCategories(IMediaRouter2Client client, List<String> categories) {
- mService2.setControlCategories(client, categories);
+ public void setDiscoveryRequest2(IMediaRouter2Client client, RouteDiscoveryRequest request) {
+ mService2.setDiscoveryRequest2(client, request);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
new file mode 100644
index 000000000000..f3241ee44569
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.media.MediaController2;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Keeps the record of {@link Session2Token} helps to send command to the corresponding session.
+ */
+// TODO(jaewan): Do not call service method directly -- introduce listener instead.
+public class MediaSession2Record implements MediaSessionRecordImpl {
+ private static final String TAG = "MediaSession2Record";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final Session2Token mSessionToken;
+ @GuardedBy("mLock")
+ private final HandlerExecutor mHandlerExecutor;
+ @GuardedBy("mLock")
+ private final MediaController2 mController;
+ @GuardedBy("mLock")
+ private final MediaSessionService mService;
+ @GuardedBy("mLock")
+ private boolean mIsConnected;
+
+ public MediaSession2Record(Session2Token sessionToken, MediaSessionService service,
+ Looper handlerLooper) {
+ mSessionToken = sessionToken;
+ mService = service;
+ mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper));
+ mController = new MediaController2.Builder(service.getContext(), sessionToken)
+ .setControllerCallback(mHandlerExecutor, new Controller2Callback())
+ .build();
+ }
+
+ @Override
+ public String getPackageName() {
+ return mSessionToken.getPackageName();
+ }
+
+ public Session2Token getSession2Token() {
+ return mSessionToken;
+ }
+
+ @Override
+ public int getUid() {
+ return mSessionToken.getUid();
+ }
+
+ @Override
+ public int getUserId() {
+ return UserHandle.getUserId(mSessionToken.getUid());
+ }
+
+ @Override
+ public boolean isSystemPriority() {
+ // System priority session is currently only allowed for telephony, and it's OK to stick to
+ // the media1 API at this moment.
+ return false;
+ }
+
+ @Override
+ public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
+ boolean asSystemService, int direction, int flags, boolean useSuggested) {
+ // TODO(jaewan): Add API to adjust volume.
+ }
+
+ @Override
+ public boolean isActive() {
+ synchronized (mLock) {
+ return mIsConnected;
+ }
+ }
+
+ @Override
+ public boolean checkPlaybackActiveState(boolean expected) {
+ synchronized (mLock) {
+ return mIsConnected && mController.isPlaybackActive() == expected;
+ }
+ }
+
+ @Override
+ public boolean isPlaybackTypeLocal() {
+ // TODO(jaewan): Implement -- need API to know whether the playback is remote or local.
+ return true;
+ }
+
+ @Override
+ public void close() {
+ synchronized (mLock) {
+ // Call close regardless of the mIsAvailable. This may be called when it's not yet
+ // connected.
+ mController.close();
+ }
+ }
+
+ @Override
+ public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+ KeyEvent ke, int sequenceId, ResultReceiver cb) {
+ // TODO(jaewan): Implement.
+ return false;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "token=" + mSessionToken);
+ pw.println(prefix + "controller=" + mController);
+
+ final String indent = prefix + " ";
+ pw.println(indent + "playbackActive=" + mController.isPlaybackActive());
+ }
+
+ @Override
+ public String toString() {
+ // TODO(jaewan): Also add getId().
+ return getPackageName() + " (userId=" + getUserId() + ")";
+ }
+
+ private class Controller2Callback extends MediaController2.ControllerCallback {
+ @Override
+ public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
+ if (DEBUG) {
+ Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
+ }
+ synchronized (mLock) {
+ mIsConnected = true;
+ }
+ mService.onSessionActiveStateChanged(MediaSession2Record.this);
+ }
+
+ @Override
+ public void onDisconnected(MediaController2 controller) {
+ if (DEBUG) {
+ Log.d(TAG, "disconnected from " + mSessionToken);
+ }
+ synchronized (mLock) {
+ mIsConnected = false;
+ }
+ mService.onSessionDied(MediaSession2Record.this);
+ }
+
+ @Override
+ public void onPlaybackActiveChanged(MediaController2 controller, boolean playbackActive) {
+ if (DEBUG) {
+ Log.d(TAG, "playback active changed, " + mSessionToken + ", active="
+ + playbackActive);
+ }
+ mService.onSessionPlaybackStateChanged(MediaSession2Record.this, playbackActive);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index aa24ed26023a..df115d0f2773 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -56,13 +56,15 @@ import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
* This is the system implementation of a Session. Apps will interact with the
* MediaSession wrapper class instead.
*/
-public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable {
+// TODO(jaewan): Do not call service method directly -- introduce listener instead.
+public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
private static final String TAG = "MediaSessionRecord";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -72,6 +74,24 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*/
private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
+ /**
+ * These are states that usually indicate the user took an action and should
+ * bump priority regardless of the old state.
+ */
+ private static final List<Integer> ALWAYS_PRIORITY_STATES = Arrays.asList(
+ PlaybackState.STATE_FAST_FORWARDING,
+ PlaybackState.STATE_REWINDING,
+ PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
+ PlaybackState.STATE_SKIPPING_TO_NEXT);
+ /**
+ * These are states that usually indicate the user took an action if they
+ * were entered from a non-priority state.
+ */
+ private static final List<Integer> TRANSITION_PRIORITY_STATES = Arrays.asList(
+ PlaybackState.STATE_BUFFERING,
+ PlaybackState.STATE_CONNECTING,
+ PlaybackState.STATE_PLAYING);
+
private final MessageHandler mHandler;
private final int mOwnerPid;
@@ -170,6 +190,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return Info that identifies this session.
*/
+ @Override
public String getPackageName() {
return mPackageName;
}
@@ -188,6 +209,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return The UID for this session.
*/
+ @Override
public int getUid() {
return mOwnerUid;
}
@@ -197,6 +219,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return The user id for this session.
*/
+ @Override
public int getUserId() {
return mUserId;
}
@@ -207,6 +230,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return True if this is a system priority session, false otherwise
*/
+ @Override
public boolean isSystemPriority() {
return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
}
@@ -220,7 +244,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param opPackageName The op package that made the original volume request.
* @param pid The pid that made the original volume request.
* @param uid The uid that made the original volume request.
- * @param caller caller binder. can be {@code null} if it's from the volume key.
* @param asSystemService {@code true} if the event sent to the session as if it was come from
* the system service instead of the app process. This helps sessions to distinguish
* between the key injection by the app and key events from the hardware devices.
@@ -318,9 +341,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
/**
* Check if this session has been set to active by the app.
+ * <p>
+ * It's not used to prioritize sessions for dispatching media keys since API 26, but still used
+ * to filter session list in MediaSessionManager#getActiveSessions().
*
* @return True if the session is active, false otherwise.
*/
+ @Override
public boolean isActive() {
return mIsActive && !mDestroyed;
}
@@ -333,6 +360,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param expected True if playback is expected to be active. false otherwise.
* @return True if the session's playback matches with the expectation. false otherwise.
*/
+ @Override
public boolean checkPlaybackActiveState(boolean expected) {
if (mPlaybackState == null) {
return false;
@@ -345,13 +373,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
*
* @return {@code true} if the playback is local.
*/
- public boolean isPlaybackLocal() {
+ @Override
+ public boolean isPlaybackTypeLocal() {
return mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
}
@Override
public void binderDied() {
- mService.sessionDied(this);
+ mService.onSessionDied(this);
}
/**
@@ -383,7 +412,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
* @param sequenceId (optional) sequence id. Use this only when a wake lock is needed.
* @param cb (optional) result receiver to receive callback. Use this only when a wake lock is
* needed.
- * @return {@code true} if the attempt to send media button was successfuly.
+ * @return {@code true} if the attempt to send media button was successfully.
* {@code false} otherwise.
*/
public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
@@ -392,6 +421,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
cb);
}
+ @Override
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -712,7 +742,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
public void destroySession() throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
- mService.destroySession(MediaSessionRecord.this);
+ mService.onSessionDied(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -734,7 +764,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
mIsActive = active;
final long token = Binder.clearCallingIdentity();
try {
- mService.updateSession(MediaSessionRecord.this);
+ mService.onSessionActiveStateChanged(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -801,12 +831,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable
? PlaybackState.STATE_NONE : mPlaybackState.getState();
int newState = state == null
? PlaybackState.STATE_NONE : state.getState();
+ boolean shouldUpdatePriority = ALWAYS_PRIORITY_STATES.contains(newState)
+ || (!TRANSITION_PRIORITY_STATES.contains(oldState)
+ && TRANSITION_PRIORITY_STATES.contains(newState));
synchronized (mLock) {
mPlaybackState = state;
}
final long token = Binder.clearCallingIdentity();
try {
- mService.onSessionPlaystateChanged(MediaSessionRecord.this, oldState, newState);
+ mService.onSessionPlaybackStateChanged(
+ MediaSessionRecord.this, shouldUpdatePriority);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
new file mode 100644
index 000000000000..2cde89a7a6f6
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.media.AudioManager;
+import android.os.ResultReceiver;
+import android.view.KeyEvent;
+
+import java.io.PrintWriter;
+
+/**
+ * Common interfaces between {@link MediaSessionRecord} and {@link MediaSession2Record}.
+ */
+public interface MediaSessionRecordImpl extends AutoCloseable {
+
+ /**
+ * Get the info for this session.
+ *
+ * @return Info that identifies this session.
+ */
+ String getPackageName();
+
+ /**
+ * Get the UID this session was created for.
+ *
+ * @return The UID for this session.
+ */
+ int getUid();
+
+ /**
+ * Get the user id this session was created for.
+ *
+ * @return The user id for this session.
+ */
+ int getUserId();
+
+ /**
+ * Check if this session has system priorty and should receive media buttons
+ * before any other sessions.
+ *
+ * @return True if this is a system priority session, false otherwise
+ */
+ boolean isSystemPriority();
+
+ /**
+ * Send a volume adjustment to the session owner. Direction must be one of
+ * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
+ * {@link AudioManager#ADJUST_SAME}.
+ *
+ * @param packageName The package that made the original volume request.
+ * @param opPackageName The op package that made the original volume request.
+ * @param pid The pid that made the original volume request.
+ * @param uid The uid that made the original volume request.
+ * @param asSystemService {@code true} if the event sent to the session as if it was come from
+ * the system service instead of the app process. This helps sessions to distinguish
+ * between the key injection by the app and key events from the hardware devices.
+ * Should be used only when the volume key events aren't handled by foreground
+ * activity. {@code false} otherwise to tell session about the real caller.
+ * @param direction The direction to adjust volume in.
+ * @param flags Any of the flags from {@link AudioManager}.
+ * @param useSuggested True to use adjustSuggestedStreamVolume instead of
+ */
+ void adjustVolume(String packageName, String opPackageName, int pid, int uid,
+ boolean asSystemService, int direction, int flags, boolean useSuggested);
+
+ /**
+ * Check if this session has been set to active by the app. (i.e. ready to receive command and
+ * getters are available).
+ *
+ * @return True if the session is active, false otherwise.
+ */
+ // TODO(jaewan): Find better naming, or remove this from the MediaSessionRecordImpl.
+ boolean isActive();
+
+ /**
+ * Check if the session's playback active state matches with the expectation. This always return
+ * {@code false} if the playback state is unknown (e.g. {@code null}), where we cannot know the
+ * actual playback state associated with the session.
+ *
+ * @param expected True if playback is expected to be active. false otherwise.
+ * @return True if the session's playback matches with the expectation. false otherwise.
+ */
+ boolean checkPlaybackActiveState(boolean expected);
+
+ /**
+ * Check whether the playback type is local or remote.
+ * <p>
+ * <ul>
+ * <li>Local: volume changes the stream volume because playback happens on this device.</li>
+ * <li>Remote: volume is sent to the apps callback because playback happens on the remote
+ * device and we cannot know how to control the volume of it.</li>
+ * </ul>
+ *
+ * @return {@code true} if the playback is local. {@code false} if the playback is remote.
+ */
+ boolean isPlaybackTypeLocal();
+
+ /**
+ * Sends media button.
+ *
+ * @param packageName caller package name
+ * @param pid caller pid
+ * @param uid caller uid
+ * @param asSystemService {@code true} if the event sent to the session as if it was come from
+ * the system service instead of the app process.
+ * @param ke key events
+ * @param sequenceId (optional) sequence id. Use this only when a wake lock is needed.
+ * @param cb (optional) result receiver to receive callback. Use this only when a wake lock is
+ * needed.
+ * @return {@code true} if the attempt to send media button was successfully.
+ * {@code false} otherwise.
+ */
+ boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+ KeyEvent ke, int sequenceId, ResultReceiver cb);
+
+ /**
+ * Dumps internal state
+ *
+ * @param pw print writer
+ * @param prefix prefix
+ */
+ void dump(PrintWriter pw, String prefix);
+
+ /**
+ * Override {@link AutoCloseable#close} to tell not to throw exception.
+ */
+ @Override
+ void close();
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 0f059dba5274..f71fb582e3ed 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -40,10 +40,7 @@ import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
-import android.media.IAudioService;
import android.media.IRemoteVolumeController;
-import android.media.MediaController2;
-import android.media.Session2CommandGroup;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -61,7 +58,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
@@ -123,11 +119,6 @@ public class MediaSessionService extends SystemService implements Monitor {
@GuardedBy("mLock")
private final ArrayList<SessionsListenerRecord> mSessionsListeners =
new ArrayList<SessionsListenerRecord>();
- // Map user id as index to list of Session2Tokens
- // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
- // one place.
- @GuardedBy("mLock")
- private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
@GuardedBy("mLock")
private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
new ArrayList<>();
@@ -189,16 +180,11 @@ public class MediaSessionService extends SystemService implements Monitor {
updateUser();
}
- private IAudioService getAudioService() {
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- return IAudioService.Stub.asInterface(b);
- }
-
private boolean isGlobalPriorityActiveLocked() {
return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
}
- void updateSession(MediaSessionRecord record) {
+ void onSessionActiveStateChanged(MediaSessionRecordImpl record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
if (user == null) {
@@ -215,12 +201,14 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Unknown session updated. Ignoring.");
return;
}
- user.mPriorityStack.onSessionStateChange(record);
+ user.mPriorityStack.onSessionActiveStateChanged(record);
}
- mHandler.postSessionsChanged(record.getUserId());
+
+ mHandler.postSessionsChanged(record);
}
}
+ // Currently only media1 can become global priority session.
void setGlobalPrioritySession(MediaSessionRecord record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
@@ -266,11 +254,13 @@ public class MediaSessionService extends SystemService implements Monitor {
List<Session2Token> getSession2TokensLocked(int userId) {
List<Session2Token> list = new ArrayList<>();
if (userId == USER_ALL) {
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- list.addAll(mSession2TokensPerUser.valueAt(i));
+ int size = mUserRecords.size();
+ for (int i = 0; i < size; i++) {
+ list.addAll(mUserRecords.valueAt(i).mPriorityStack.getSession2Tokens(userId));
}
} else {
- list.addAll(mSession2TokensPerUser.get(userId));
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ list.addAll(user.mPriorityStack.getSession2Tokens(userId));
}
return list;
}
@@ -297,14 +287,15 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
+ void onSessionPlaybackStateChanged(MediaSessionRecordImpl record,
+ boolean shouldUpdatePriority) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
if (user == null || !user.mPriorityStack.contains(record)) {
Log.d(TAG, "Unknown session changed playback state. Ignoring.");
return;
}
- user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
+ user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);
}
}
@@ -347,7 +338,6 @@ public class MediaSessionService extends SystemService implements Monitor {
user.destroySessionsForUserLocked(userId);
}
}
- mSession2TokensPerUser.remove(userId);
updateUser();
}
}
@@ -366,13 +356,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void sessionDied(MediaSessionRecord session) {
- synchronized (mLock) {
- destroySessionLocked(session);
- }
- }
-
- void destroySession(MediaSessionRecord session) {
+ void onSessionDied(MediaSessionRecordImpl session) {
synchronized (mLock) {
destroySessionLocked(session);
}
@@ -393,9 +377,6 @@ public class MediaSessionService extends SystemService implements Monitor {
mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
}
}
- if (mSession2TokensPerUser.get(userInfo.id) == null) {
- mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
- }
}
}
// Ensure that the current full user exists.
@@ -405,9 +386,6 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
- if (mSession2TokensPerUser.get(currentFullUserId) == null) {
- mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
- }
}
mFullUserIds.put(currentFullUserId, currentFullUserId);
}
@@ -444,7 +422,7 @@ public class MediaSessionService extends SystemService implements Monitor {
* 5. We need to unlink to death from the cb binder
* 6. We need to tell the session to do any final cleanup (onDestroy)
*/
- private void destroySessionLocked(MediaSessionRecord session) {
+ private void destroySessionLocked(MediaSessionRecordImpl session) {
if (DEBUG) {
Log.d(TAG, "Destroying " + session);
}
@@ -461,7 +439,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
session.close();
- mHandler.postSessionsChanged(session.getUserId());
+ mHandler.postSessionsChanged(session);
}
private void enforcePackageName(String packageName, int uid) {
@@ -541,15 +519,6 @@ public class MediaSessionService extends SystemService implements Monitor {
return false;
}
- private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo)
- throws RemoteException {
- synchronized (mLock) {
- return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb,
- tag, sessionInfo);
- }
- }
-
/*
* When a session is created the following things need to happen.
* 1. Its callback binder needs a link to death
@@ -557,29 +526,31 @@ public class MediaSessionService extends SystemService implements Monitor {
* 3. It needs to be added to the priority stack.
* 4. It needs to be added to the relevant user record.
*/
- private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+ private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
- throw new RuntimeException("Session request from invalid user.");
- }
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
+ throw new RuntimeException("Session request from invalid user.");
+ }
- final MediaSessionRecord session;
- try {
- session = new MediaSessionRecord(callerPid, callerUid, userId,
- callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
- } catch (RemoteException e) {
- throw new RuntimeException("Media Session owner died prematurely.", e);
- }
+ final MediaSessionRecord session;
+ try {
+ session = new MediaSessionRecord(callerPid, callerUid, userId,
+ callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Media Session owner died prematurely.", e);
+ }
- user.mPriorityStack.addSession(session);
- mHandler.postSessionsChanged(userId);
+ user.mPriorityStack.addSession(session);
+ mHandler.postSessionsChanged(session);
- if (DEBUG) {
- Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+ if (DEBUG) {
+ Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+ }
+ return session;
}
- return session;
}
private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
@@ -600,16 +571,16 @@ public class MediaSessionService extends SystemService implements Monitor {
return -1;
}
- private void pushSessionsChanged(int userId) {
+ private void pushSession1Changed(int userId) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
- Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
+ Log.w(TAG, "pushSession1ChangedOnHandler failed. No user with id=" + userId);
return;
}
List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
int size = records.size();
- ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
+ ArrayList<MediaSession.Token> tokens = new ArrayList<>();
for (int i = 0; i < size; i++) {
tokens.add(records.get(i).getSessionToken());
}
@@ -629,6 +600,27 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ void pushSession2Changed(int userId) {
+ synchronized (mLock) {
+ List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+ List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+ for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+ Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+ try {
+ if (listenerRecord.userId == USER_ALL) {
+ listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+ } else if (listenerRecord.userId == userId) {
+ listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+ mSession2TokensListenerRecords.remove(i);
+ }
+ }
+ }
+ }
+
private void pushRemoteVolumeUpdateLocked(int userId) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
@@ -638,8 +630,13 @@ public class MediaSessionService extends SystemService implements Monitor {
synchronized (mLock) {
int size = mRemoteVolumeControllers.beginBroadcast();
- MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
- MediaSession.Token token = record == null ? null : record.getSessionToken();
+ MediaSessionRecordImpl record = user.mPriorityStack.getDefaultRemoteSession(userId);
+ if (record instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSession.Token token = record == null
+ ? null : ((MediaSessionRecord) record).getSessionToken();
for (int i = size - 1; i >= 0; i--) {
try {
@@ -653,34 +650,15 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- void pushSession2TokensChangedLocked(int userId) {
- List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
- List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
-
- for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
- Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
- try {
- if (listenerRecord.userId == USER_ALL) {
- listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
- } else if (listenerRecord.userId == userId) {
- listenerRecord.listener.onSession2TokensChanged(session2Tokens);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
- mSession2TokensListenerRecords.remove(i);
- }
- }
- }
-
/**
* Called when the media button receiver for the {@code record} is changed.
*
* @param record the media session whose media button receiver is updated.
*/
- public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
+ public void onMediaButtonReceiverChanged(MediaSessionRecordImpl record) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- MediaSessionRecord mediaButtonSession =
+ MediaSessionRecordImpl mediaButtonSession =
user.mPriorityStack.getMediaButtonSession();
if (record == mediaButtonSession) {
user.rememberMediaButtonReceiverLocked(mediaButtonSession);
@@ -868,39 +846,34 @@ public class MediaSessionService extends SystemService implements Monitor {
pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+ mRestoredMediaButtonReceiverComponentType);
mPriorityStack.dump(pw, indent);
- pw.println(indent + "Session2Tokens:");
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
- if (list == null || list.size() == 0) {
- continue;
- }
- for (Session2Token token : list) {
- pw.println(indent + " " + token);
- }
- }
}
@Override
- public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
- MediaSessionRecord newMediaButtonSession) {
+ public void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession,
+ MediaSessionRecordImpl newMediaButtonSession) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
}
synchronized (mLock) {
if (oldMediaButtonSession != null) {
- mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
+ mHandler.postSessionsChanged(oldMediaButtonSession);
}
if (newMediaButtonSession != null) {
rememberMediaButtonReceiverLocked(newMediaButtonSession);
- mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
+ mHandler.postSessionsChanged(newMediaButtonSession);
}
pushAddressedPlayerChangedLocked();
}
}
// Remember media button receiver and keep it in the persistent storage.
- public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
- PendingIntent receiver = record.getMediaButtonReceiver();
+ public void rememberMediaButtonReceiverLocked(MediaSessionRecordImpl record) {
+ if (record instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSessionRecord sessionRecord = (MediaSessionRecord) record;
+ PendingIntent receiver = sessionRecord.getMediaButtonReceiver();
mLastMediaButtonReceiver = receiver;
mRestoredMediaButtonReceiver = null;
mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
@@ -925,10 +898,15 @@ public class MediaSessionService extends SystemService implements Monitor {
private void pushAddressedPlayerChangedLocked(
IOnMediaKeyEventSessionChangedListener callback) {
try {
- MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+ MediaSessionRecordImpl mediaButtonSession = getMediaButtonSessionLocked();
if (mediaButtonSession != null) {
- callback.onMediaKeyEventSessionChanged(mediaButtonSession.getPackageName(),
- mediaButtonSession.getSessionToken());
+ if (mediaButtonSession instanceof MediaSessionRecord) {
+ MediaSessionRecord session1 = (MediaSessionRecord) mediaButtonSession;
+ callback.onMediaKeyEventSessionChanged(session1.getPackageName(),
+ session1.getSessionToken());
+ } else {
+ // TODO(jaewan): Implement
+ }
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
callback.onMediaKeyEventSessionChanged(
mCurrentFullUserRecord.mLastMediaButtonReceiver
@@ -951,7 +929,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- private MediaSessionRecord getMediaButtonSessionLocked() {
+ private MediaSessionRecordImpl getMediaButtonSessionLocked() {
return isGlobalPriorityActiveLocked()
? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
}
@@ -1132,14 +1110,13 @@ public class MediaSessionService extends SystemService implements Monitor {
throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+ " but actually=" + sessionToken.getUid());
}
- Controller2Callback callback = new Controller2Callback(sessionToken);
- // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
- // it's closed.
- // TODO: Keep controller as well for better readability
- // because the GC behavior isn't straightforward.
- MediaController2 controller = new MediaController2.Builder(mContext, sessionToken)
- .setControllerCallback(new HandlerExecutor(mHandler), callback)
- .build();
+ MediaSession2Record record = new MediaSession2Record(
+ sessionToken, MediaSessionService.this, mHandler.getLooper());
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ user.mPriorityStack.addSession(record);
+ }
+ // Do not immediately notify changes -- do so when framework can dispatch command
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1180,7 +1157,8 @@ public class MediaSessionService extends SystemService implements Monitor {
null /* optional packageName */);
List<Session2Token> result;
synchronized (mLock) {
- result = getSession2TokensLocked(resolvedUserId);
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ result = user.mPriorityStack.getSession2Tokens(resolvedUserId);
}
return new ParceledListSlice(result);
} finally {
@@ -2018,7 +1996,7 @@ public class MediaSessionService extends SystemService implements Monitor {
private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
- MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
+ MediaSessionRecordImpl session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
: mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
boolean preferSuggestedStream = false;
@@ -2109,7 +2087,13 @@ public class MediaSessionService extends SystemService implements Monitor {
private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
+ if (mCurrentFullUserRecord.getMediaButtonSessionLocked()
+ instanceof MediaSession2Record) {
+ // TODO(jaewan): Implement
+ return;
+ }
+ MediaSessionRecord session =
+ (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
if (session != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
@@ -2389,15 +2373,19 @@ public class MediaSessionService extends SystemService implements Monitor {
}
final class MessageHandler extends Handler {
- private static final int MSG_SESSIONS_CHANGED = 1;
- private static final int MSG_VOLUME_INITIAL_DOWN = 2;
+ private static final int MSG_SESSIONS_1_CHANGED = 1;
+ private static final int MSG_SESSIONS_2_CHANGED = 2;
+ private static final int MSG_VOLUME_INITIAL_DOWN = 3;
private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_SESSIONS_CHANGED:
- pushSessionsChanged((int) msg.obj);
+ case MSG_SESSIONS_1_CHANGED:
+ pushSession1Changed((int) msg.obj);
+ break;
+ case MSG_SESSIONS_2_CHANGED:
+ pushSession2Changed((int) msg.obj);
break;
case MSG_VOLUME_INITIAL_DOWN:
synchronized (mLock) {
@@ -2412,41 +2400,19 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- public void postSessionsChanged(int userId) {
+ public void postSessionsChanged(MediaSessionRecordImpl record) {
// Use object instead of the arguments when posting message to remove pending requests.
- Integer userIdInteger = mIntegerCache.get(userId);
+ Integer userIdInteger = mIntegerCache.get(record.getUserId());
if (userIdInteger == null) {
- userIdInteger = Integer.valueOf(userId);
- mIntegerCache.put(userId, userIdInteger);
+ userIdInteger = Integer.valueOf(record.getUserId());
+ mIntegerCache.put(record.getUserId(), userIdInteger);
}
- removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
- obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
- }
- }
- private class Controller2Callback extends MediaController2.ControllerCallback {
- private final Session2Token mToken;
-
- Controller2Callback(Session2Token token) {
- mToken = token;
- }
-
- @Override
- public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).add(mToken);
- pushSession2TokensChangedLocked(userId);
- }
- }
-
- @Override
- public void onDisconnected(MediaController2 controller) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).remove(mToken);
- pushSession2TokensChangedLocked(userId);
- }
+ int msg = (record instanceof MediaSessionRecord)
+ ? MSG_SESSIONS_1_CHANGED : MSG_SESSIONS_2_CHANGED;
+ removeMessages(msg, userIdInteger);
+ obtainMessage(msg, userIdInteger).sendToTarget();
}
}
+
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 732563f6e05e..7bb7cf4b74ad 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -16,8 +16,8 @@
package com.android.server.media;
+import android.media.Session2Token;
import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
import android.os.Debug;
import android.os.UserHandle;
import android.util.IntArray;
@@ -45,51 +45,30 @@ class MediaSessionStack {
/**
* Called when the media button session is changed.
*/
- void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
- MediaSessionRecord newMediaButtonSession);
+ void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession,
+ MediaSessionRecordImpl newMediaButtonSession);
}
/**
- * These are states that usually indicate the user took an action and should
- * bump priority regardless of the old state.
+ * Sorted list of the media sessions
*/
- private static final int[] ALWAYS_PRIORITY_STATES = {
- PlaybackState.STATE_FAST_FORWARDING,
- PlaybackState.STATE_REWINDING,
- PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
- PlaybackState.STATE_SKIPPING_TO_NEXT };
- /**
- * These are states that usually indicate the user took an action if they
- * were entered from a non-priority state.
- */
- private static final int[] TRANSITION_PRIORITY_STATES = {
- PlaybackState.STATE_BUFFERING,
- PlaybackState.STATE_CONNECTING,
- PlaybackState.STATE_PLAYING };
-
- /**
- * Sorted list of the media sessions.
- * The session of which PlaybackState is changed to ALWAYS_PRIORITY_STATES or
- * TRANSITION_PRIORITY_STATES comes first.
- * @see #shouldUpdatePriority
- */
- private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+ private final List<MediaSessionRecordImpl> mSessions = new ArrayList<>();
private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener;
/**
* The media button session which receives media key events.
- * It could be null if the previous media buttion session is released.
+ * It could be null if the previous media button session is released.
*/
- private MediaSessionRecord mMediaButtonSession;
+ private MediaSessionRecordImpl mMediaButtonSession;
- private MediaSessionRecord mCachedVolumeDefault;
+ private MediaSessionRecordImpl mCachedVolumeDefault;
/**
* Cache the result of the {@link #getActiveSessions} per user.
*/
- private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists =
+ private final SparseArray<List<MediaSessionRecord>> mCachedActiveLists =
new SparseArray<>();
MediaSessionStack(AudioPlayerStateMonitor monitor, OnMediaButtonSessionChangedListener listener) {
@@ -102,7 +81,7 @@ class MediaSessionStack {
*
* @param record The record to add.
*/
- public void addSession(MediaSessionRecord record) {
+ public void addSession(MediaSessionRecordImpl record) {
mSessions.add(record);
clearCache(record.getUserId());
@@ -117,7 +96,7 @@ class MediaSessionStack {
*
* @param record The record to remove.
*/
- public void removeSession(MediaSessionRecord record) {
+ public void removeSession(MediaSessionRecordImpl record) {
mSessions.remove(record);
if (mMediaButtonSession == record) {
// When the media button session is removed, nullify the media button session and do not
@@ -131,7 +110,7 @@ class MediaSessionStack {
/**
* Return if the record exists in the priority tracker.
*/
- public boolean contains(MediaSessionRecord record) {
+ public boolean contains(MediaSessionRecordImpl record) {
return mSessions.contains(record);
}
@@ -142,9 +121,12 @@ class MediaSessionStack {
* @return the MediaSessionRecord. Can be {@code null} if the session is gone meanwhile.
*/
public MediaSessionRecord getMediaSessionRecord(MediaSession.Token sessionToken) {
- for (MediaSessionRecord record : mSessions) {
- if (Objects.equals(record.getSessionToken(), sessionToken)) {
- return record;
+ for (MediaSessionRecordImpl record : mSessions) {
+ if (record instanceof MediaSessionRecord) {
+ MediaSessionRecord session1 = (MediaSessionRecord) record;
+ if (Objects.equals(session1.getSessionToken(), sessionToken)) {
+ return session1;
+ }
}
}
return null;
@@ -154,15 +136,15 @@ class MediaSessionStack {
* Notify the priority tracker that a session's playback state changed.
*
* @param record The record that changed.
- * @param oldState Its old playback state.
- * @param newState Its new playback state.
+ * @param shouldUpdatePriority {@code true} if the record needs to prioritized
*/
- public void onPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
- if (shouldUpdatePriority(oldState, newState)) {
+ public void onPlaybackStateChanged(
+ MediaSessionRecordImpl record, boolean shouldUpdatePriority) {
+ if (shouldUpdatePriority) {
mSessions.remove(record);
mSessions.add(0, record);
clearCache(record.getUserId());
- } else if (!MediaSession.isActiveState(newState)) {
+ } else if (record.checkPlaybackActiveState(false)) {
// Just clear the volume cache when a state goes inactive
mCachedVolumeDefault = null;
}
@@ -172,7 +154,7 @@ class MediaSessionStack {
// In that case, we pick the media session whose PlaybackState matches
// the audio playback configuration.
if (mMediaButtonSession != null && mMediaButtonSession.getUid() == record.getUid()) {
- MediaSessionRecord newMediaButtonSession =
+ MediaSessionRecordImpl newMediaButtonSession =
findMediaButtonSession(mMediaButtonSession.getUid());
if (newMediaButtonSession != mMediaButtonSession) {
updateMediaButtonSession(newMediaButtonSession);
@@ -185,7 +167,7 @@ class MediaSessionStack {
*
* @param record The record that changed.
*/
- public void onSessionStateChange(MediaSessionRecord record) {
+ public void onSessionActiveStateChanged(MediaSessionRecordImpl record) {
// For now just clear the cache. Eventually we'll selectively clear
// depending on what changed.
clearCache(record.getUserId());
@@ -203,7 +185,7 @@ class MediaSessionStack {
}
IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
for (int i = 0; i < audioPlaybackUids.size(); i++) {
- MediaSessionRecord mediaButtonSession =
+ MediaSessionRecordImpl mediaButtonSession =
findMediaButtonSession(audioPlaybackUids.get(i));
if (mediaButtonSession != null) {
// Found the media button session.
@@ -225,9 +207,9 @@ class MediaSessionStack {
* @return The media button session. Returns {@code null} if the app doesn't have a media
* session.
*/
- private MediaSessionRecord findMediaButtonSession(int uid) {
- MediaSessionRecord mediaButtonSession = null;
- for (MediaSessionRecord session : mSessions) {
+ private MediaSessionRecordImpl findMediaButtonSession(int uid) {
+ MediaSessionRecordImpl mediaButtonSession = null;
+ for (MediaSessionRecordImpl session : mSessions) {
if (uid == session.getUid()) {
if (session.checkPlaybackActiveState(
mAudioPlayerStateMonitor.isPlaybackActive(session.getUid()))) {
@@ -253,8 +235,8 @@ class MediaSessionStack {
* for all users in this {@link MediaSessionStack}.
* @return All the active sessions in priority order.
*/
- public ArrayList<MediaSessionRecord> getActiveSessions(int userId) {
- ArrayList<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId);
+ public List<MediaSessionRecord> getActiveSessions(int userId) {
+ List<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId);
if (cachedActiveList == null) {
cachedActiveList = getPriorityList(true, userId);
mCachedActiveLists.put(userId, cachedActiveList);
@@ -263,26 +245,46 @@ class MediaSessionStack {
}
/**
+ * Gets the session2 tokens.
+ *
+ * @param userId The user to check. It can be {@link UserHandle#USER_ALL} to get all session2
+ * tokens for all users in this {@link MediaSessionStack}.
+ * @return All session2 tokens.
+ */
+ public List<Session2Token> getSession2Tokens(int userId) {
+ ArrayList<Session2Token> session2Records = new ArrayList<>();
+ for (MediaSessionRecordImpl record : mSessions) {
+ if ((userId == UserHandle.USER_ALL || record.getUserId() == userId)
+ && record.isActive()
+ && record instanceof MediaSession2Record) {
+ MediaSession2Record session2 = (MediaSession2Record) record;
+ session2Records.add(session2.getSession2Token());
+ }
+ }
+ return session2Records;
+ }
+
+ /**
* Get the media button session which receives the media button events.
*
* @return The media button session or null.
*/
- public MediaSessionRecord getMediaButtonSession() {
+ public MediaSessionRecordImpl getMediaButtonSession() {
return mMediaButtonSession;
}
- private void updateMediaButtonSession(MediaSessionRecord newMediaButtonSession) {
- MediaSessionRecord oldMediaButtonSession = mMediaButtonSession;
+ private void updateMediaButtonSession(MediaSessionRecordImpl newMediaButtonSession) {
+ MediaSessionRecordImpl oldMediaButtonSession = mMediaButtonSession;
mMediaButtonSession = newMediaButtonSession;
mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
oldMediaButtonSession, newMediaButtonSession);
}
- public MediaSessionRecord getDefaultVolumeSession() {
+ public MediaSessionRecordImpl getDefaultVolumeSession() {
if (mCachedVolumeDefault != null) {
return mCachedVolumeDefault;
}
- ArrayList<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL);
+ List<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
@@ -294,13 +296,13 @@ class MediaSessionStack {
return null;
}
- public MediaSessionRecord getDefaultRemoteSession(int userId) {
- ArrayList<MediaSessionRecord> records = getPriorityList(true, userId);
+ public MediaSessionRecordImpl getDefaultRemoteSession(int userId) {
+ List<MediaSessionRecord> records = getPriorityList(true, userId);
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
- if (!record.isPlaybackLocal()) {
+ if (!record.isPlaybackTypeLocal()) {
return record;
}
}
@@ -308,16 +310,11 @@ class MediaSessionStack {
}
public void dump(PrintWriter pw, String prefix) {
- ArrayList<MediaSessionRecord> sortedSessions = getPriorityList(false,
- UserHandle.USER_ALL);
- int count = sortedSessions.size();
pw.println(prefix + "Media button session is " + mMediaButtonSession);
- pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
+ pw.println(prefix + "Sessions Stack - have " + mSessions.size() + " sessions:");
String indent = prefix + " ";
- for (int i = 0; i < count; i++) {
- MediaSessionRecord record = sortedSessions.get(i);
+ for (MediaSessionRecordImpl record : mSessions) {
record.dump(pw, indent);
- pw.println();
}
}
@@ -335,17 +332,19 @@ class MediaSessionStack {
* will return sessions for all users.
* @return The priority sorted list of sessions.
*/
- public ArrayList<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) {
- ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
+ public List<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) {
+ List<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
int lastPlaybackActiveIndex = 0;
int lastActiveIndex = 0;
- int size = mSessions.size();
- for (int i = 0; i < size; i++) {
- final MediaSessionRecord session = mSessions.get(i);
+ for (MediaSessionRecordImpl record : mSessions) {
+ if (!(record instanceof MediaSessionRecord)) {
+ continue;
+ }
+ final MediaSessionRecord session = (MediaSessionRecord) record;
- if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
- // Filter out sessions for the wrong user
+ if ((userId != UserHandle.USER_ALL && userId != session.getUserId())) {
+ // Filter out sessions for the wrong user or session2.
continue;
}
@@ -369,26 +368,6 @@ class MediaSessionStack {
return result;
}
- private boolean shouldUpdatePriority(int oldState, int newState) {
- if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
- return true;
- }
- if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
- && containsState(newState, TRANSITION_PRIORITY_STATES)) {
- return true;
- }
- return false;
- }
-
- private boolean containsState(int state, int[] states) {
- for (int i = 0; i < states.length; i++) {
- if (states[i] == state) {
- return true;
- }
- }
- return false;
- }
-
private void clearCache(int userId) {
mCachedVolumeDefault = null;
mCachedActiveLists.remove(userId);
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 8fdfcbfb2ad9..daf603012391 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -91,7 +91,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void requestCreateSession(String packageName, String routeId, String controlCategory,
+ public void requestCreateSession(String packageName, String routeId, String routeType,
long requestId) {
// Do nothing
}
@@ -102,33 +102,33 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void selectRoute(int sessionId, MediaRoute2Info route) {
+ public void selectRoute(int sessionId, String routeId) {
//TODO: implement method
}
@Override
- public void deselectRoute(int sessionId, MediaRoute2Info route) {
+ public void deselectRoute(int sessionId, String routeId) {
//TODO: implement method
}
@Override
- public void transferToRoute(int sessionId, MediaRoute2Info route) {
+ public void transferToRoute(int sessionId, String routeId) {
//TODO: implement method
}
//TODO: implement method
@Override
- public void sendControlRequest(@NonNull MediaRoute2Info route, @NonNull Intent request) {
+ public void sendControlRequest(@NonNull String routeId, @NonNull Intent request) {
}
//TODO: implement method
@Override
- public void requestSetVolume(MediaRoute2Info route, int volume) {
+ public void requestSetVolume(String routeId, int volume) {
}
//TODO: implement method
@Override
- public void requestUpdateVolume(MediaRoute2Info route, int delta) {
+ public void requestUpdateVolume(String routeId, int delta) {
}
void initializeRoutes() {
@@ -141,8 +141,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
- .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .addRouteType(CATEGORY_LIVE_AUDIO)
+ .addRouteType(CATEGORY_LIVE_VIDEO)
.build();
AudioRoutesInfo newAudioRoutes = null;
@@ -181,8 +181,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
- .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .addRouteType(CATEGORY_LIVE_AUDIO)
+ .addRouteType(CATEGORY_LIVE_VIDEO)
.build();
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
@@ -193,7 +193,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
mCurAudioRoutesInfo.bluetoothName)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
- .addSupportedCategory(CATEGORY_LIVE_AUDIO)
+ .addRouteType(CATEGORY_LIVE_AUDIO)
.build();
} else {
mBluetoothA2dpRoute = null;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 3ca1803262e7..22b01bee6c6a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -229,7 +229,7 @@ public class NetworkStatsFactory {
entry.txPackets += reader.nextLong();
}
- stats.addValues(entry);
+ stats.addEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -279,7 +279,7 @@ public class NetworkStatsFactory {
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- stats.addValues(entry);
+ stats.addEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -439,7 +439,7 @@ public class NetworkStatsFactory {
if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
&& (limitUid == UID_ALL || limitUid == entry.uid)
&& (limitTag == TAG_ALL || limitTag == entry.tag)) {
- stats.addValues(entry);
+ stats.addEntry(entry);
}
reader.finishLine();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ec8a8e7c4c1a..7a6f29764f09 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.IFACE_VT;
import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.ROAMING_ALL;
@@ -211,7 +212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/**
* Virtual network interface for video telephony. This is for VT data usage counting purpose.
*/
- public static final String VT_INTERFACE = "vt_data0";
+ // TODO: Remove this after no one is using it.
+ public static final String VT_INTERFACE = NetworkStats.IFACE_VT;
/**
* Settings that can be changed externally.
@@ -712,7 +714,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
final NetworkStats stats = new NetworkStats(end - start, 1);
- stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
+ stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets,
entry.txBytes, entry.txPackets, entry.operations));
return stats;
@@ -1179,8 +1181,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
ident.getRoaming(), true /* metered */,
true /* onDefaultNetwork */);
- findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
}
if (isMobile) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5a124a717de2..ea83adba4d8a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -562,10 +562,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
- private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
- private volatile boolean mMovingDisplayToTopKeyTriggered;
- private volatile long mMovingDisplayToTopKeyTime;
-
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -633,7 +629,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
private static final int MSG_RINGER_TOGGLE_CHORD = 27;
- private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
private class PolicyHandler extends Handler {
@Override
@@ -697,7 +692,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
accessibilityShortcutActivated();
break;
case MSG_BUGREPORT_TV:
- requestFullBugreport();
+ requestFullBugreportOrLaunchHandlerApp();
break;
case MSG_ACCESSIBILITY_TV:
if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)) {
@@ -723,10 +718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
break;
- case MSG_MOVE_DISPLAY_TO_TOP:
- mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
- mMovingDisplayToTopKeyTriggered = false;
- break;
}
}
}
@@ -2545,36 +2536,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
int policyFlags) {
- final long result = interceptKeyBeforeDispatchingInner(focusedToken, event, policyFlags);
- final int eventDisplayId = event.getDisplayId();
- if (result == 0 && !mPerDisplayFocusEnabled
- && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
- // An event is targeting a non-focused display. Try to move the display to top so that
- // it can become the focused display to interact with the user.
- final long eventDownTime = event.getDownTime();
- if (mMovingDisplayToTopKeyTime < eventDownTime) {
- // We have not handled this event yet. Move the display to top, and then tell
- // dispatcher to try again later.
- mMovingDisplayToTopKeyTime = eventDownTime;
- mMovingDisplayToTopKeyTriggered = true;
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- } else if (mMovingDisplayToTopKeyTriggered) {
- // The message has not been handled yet. Tell dispatcher to try again later.
- return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
- }
- // The target display is still not the top focused display. Drop the event because the
- // display may not contain any window which can receive keys.
- Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
- + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
- return -1;
- }
- return result;
- }
-
- private long interceptKeyBeforeDispatchingInner(IBinder focusedToken, KeyEvent event,
- int policyFlags) {
final boolean keyguardOn = keyguardOn();
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
@@ -3061,12 +3022,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return mAccessibilityTvScheduled;
}
- private void requestFullBugreport() {
+ private void requestFullBugreportOrLaunchHandlerApp() {
if ("1".equals(SystemProperties.get("ro.debuggable"))
|| Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) {
try {
- ActivityManager.getService().requestFullBugReport();
+ if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+ ActivityManager.getService().requestFullBugReport();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Error taking bugreport", e);
}
@@ -3613,7 +3576,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
final int displayId = event.getDisplayId();
-
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
// If screen is off then we treat the case where the keyguard is open but hidden
@@ -4035,6 +3997,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
}
+ if ((result & ACTION_PASS_TO_USER) != 0) {
+ // If the key event is targeted to a specific display, then the user is interacting with
+ // that display. Therefore, give focus to the display that the user is interacting with.
+ if (!mPerDisplayFocusEnabled
+ && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
+ // An event is targeting a non-focused display. Move the display to top so that
+ // it can become the focused display to interact with the user.
+ // This should be done asynchronously, once the focus logic is fully moved to input
+ // from windowmanager. Currently, we need to ensure the setInputWindows completes,
+ // which would force the focus event to be queued before the current key event.
+ // TODO(b/70668286): post call to 'moveDisplayToTop' to mHandler instead
+ Log.i(TAG, "Moving non-focused display " + displayId + " to top "
+ + "because a key is targeting it");
+ mWindowManagerFuncs.moveDisplayToTop(displayId);
+ }
+ }
+
return result;
}
@@ -5213,7 +5192,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, null, dock,
+ .startActivityAsUser(null, mContext.getBasePackageName(), dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -5224,7 +5203,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, null, mHomeIntent,
+ .startActivityAsUser(null, mContext.getBasePackageName(), mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index b4f4eca5f188..f661b5e0d8a8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -22,7 +22,7 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 02656eaf5c6c..da848d87ba71 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -24,10 +24,10 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
+import android.os.TimestampedValue;
import android.telephony.TelephonyManager;
import android.util.LocalLog;
import android.util.Slog;
-import android.util.TimestampedValue;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 94c2192b620f..23b94bdb74c8 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -751,10 +751,10 @@ class ActivityMetricsLogger {
if (abort) {
launchObserverNotifyActivityLaunchCancelled(info);
} else {
- logAppTransitionFinished(info);
if (info.isInterestingToLoggerAndObserver()) {
launchObserverNotifyActivityLaunchFinished(info, timestampNs);
}
+ logAppTransitionFinished(info);
}
info.mPendingDrawActivities.clear();
mTransitionInfoList.remove(info);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 65d0c4c2515f..e281712f743a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6107,11 +6107,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// This also avoids if the next activity never reports idle (e.g. animating view),
// the previous will need to wait until idle timeout to be stopped or destroyed.
mStackSupervisor.scheduleProcessStoppingAndFinishingActivities();
- } else {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
- true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
}
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index e8564fc80ac3..fd871bdc1ba2 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2076,54 +2076,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
- processStoppingActivities(launchedActivity, false /* onlyUpdateVisibility */,
- processPausingActivities, reason);
-
- final int numFinishingActivities = mFinishingActivities.size();
- if (numFinishingActivities == 0) {
- return;
- }
-
- // Finish any activities that are scheduled to do so but have been waiting for the next one
- // to start.
- final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
- mFinishingActivities.clear();
- for (int i = 0; i < numFinishingActivities; i++) {
- final ActivityRecord r = finishingActivities.get(i);
- if (r.isInHistory()) {
- r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
- }
- }
- }
-
- /** Stop or destroy the stopping activities if they are not interactive. */
- void processStoppingActivities(ActivityRecord launchedActivity, boolean onlyUpdateVisibility,
- boolean processPausingActivities, String reason) {
- final int numStoppingActivities = mStoppingActivities.size();
- if (numStoppingActivities == 0) {
- return;
- }
ArrayList<ActivityRecord> readyToStopActivities = null;
-
- final boolean nowVisible = mRootWindowContainer.allResumedActivitiesVisible();
- for (int activityNdx = numStoppingActivities - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord s = mStoppingActivities.get(activityNdx);
- if (nowVisible && s.finishing) {
-
- // If this activity is finishing, it is sitting on top of
- // everyone else but we now know it is no longer needed...
- // so get rid of it. Otherwise, we need to go through the
- // normal flow and hide it once we determine that it is
- // hidden by the activities in front of it.
- if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
- s.setVisibility(false);
- }
- if (onlyUpdateVisibility) {
- continue;
- }
-
+ for (int i = mStoppingActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord s = mStoppingActivities.get(i);
final boolean animating = s.isAnimating(TRANSITION);
- if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+ if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible
+ " animating=" + animating + " finishing=" + s.finishing);
final ActivityStack stack = s.getActivityStack();
@@ -2145,7 +2102,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
readyToStopActivities.add(s);
- mStoppingActivities.remove(activityNdx);
+ mStoppingActivities.remove(i);
}
}
@@ -2161,6 +2118,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
}
}
+
+ final int numFinishingActivities = mFinishingActivities.size();
+ if (numFinishingActivities == 0) {
+ return;
+ }
+
+ // Finish any activities that are scheduled to do so but have been waiting for the next one
+ // to start.
+ final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
+ mFinishingActivities.clear();
+ for (int i = 0; i < numFinishingActivities; i++) {
+ final ActivityRecord r = finishingActivities.get(i);
+ if (r.isInHistory()) {
+ r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+ }
+ }
}
void removeHistoryRecords(WindowProcessController app) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7f944454ecdf..ba9d757d979f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -205,6 +205,7 @@ import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindow;
import android.view.InputChannel;
@@ -218,6 +219,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -570,6 +572,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
WindowState mInputMethodTarget;
+ InsetsControlTarget mInputMethodControlTarget;
+
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
@@ -598,6 +602,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final float mWindowCornerRadius;
private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
+ RemoteInsetsControlTarget mRemoteInsetsControlTarget = null;
+ private final IBinder.DeathRecipient mRemoteInsetsDeath =
+ () -> {
+ synchronized (mWmService.mGlobalLock) {
+ mRemoteInsetsControlTarget = null;
+ }
+ };
private RootWindowContainer mRootWindowContainer;
@@ -772,7 +783,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// If this is the first layout, we need to initialize the last frames and inset values,
// as otherwise we'd immediately cause an unnecessary resize.
if (firstLayout) {
- w.updateLastFrames();
+ // The client may compute its actual requested size according to the first layout,
+ // so we still request the window to resize if the current frame is empty.
+ if (!w.getFrameLw().isEmpty()) {
+ w.updateLastFrames();
+ }
w.updateLastInsetValues();
w.updateLocationInParentDisplayIfNeeded();
}
@@ -1152,6 +1167,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mShellRoots.remove(windowType);
}
+ void setRemoteInsetsController(IDisplayWindowInsetsController controller) {
+ if (mRemoteInsetsControlTarget != null) {
+ mRemoteInsetsControlTarget.mRemoteInsetsController.asBinder().unlinkToDeath(
+ mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = null;
+ }
+ if (controller != null) {
+ try {
+ controller.asBinder().linkToDeath(mRemoteInsetsDeath, 0);
+ mRemoteInsetsControlTarget = new RemoteInsetsControlTarget(controller);
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+ }
+
/** Changes the display the input window token is housed on to this one. */
void reParentWindowToken(WindowToken token) {
final DisplayContent prevDc = token.getDisplayContent();
@@ -3379,6 +3410,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
+ boolean isImeAttachedToApp() {
+ return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
+ && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ // An activity with override bounds should be letterboxed inside its parent bounds,
+ // so it doesn't fill the screen.
+ && mInputMethodTarget.mActivityRecord.matchParentBounds());
+ }
+
private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) {
if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) {
return;
@@ -3387,7 +3426,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
assignWindowLayers(false /* setLayoutNeeded */);
- mInsetsStateController.onImeTargetChanged(target);
+ mInputMethodControlTarget = computeImeControlTarget();
+ mInsetsStateController.onImeTargetChanged(mInputMethodControlTarget);
updateImeParent();
}
@@ -3412,11 +3452,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
- if (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
- && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- // An activity with override bounds should be letterboxed inside its parent bounds,
- // so it doesn't fill the screen.
- && mInputMethodTarget.mActivityRecord.matchParentBounds()) {
+ if (isImeAttachedToApp()) {
return mInputMethodTarget.mActivityRecord.getSurfaceControl();
}
@@ -3424,6 +3460,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mWindowContainers.getSurfaceControl();
}
+ /**
+ * Computes which control-target the IME should be attached to.
+ */
+ @VisibleForTesting
+ InsetsControlTarget computeImeControlTarget() {
+ if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
+ return mRemoteInsetsControlTarget;
+ }
+
+ // Otherwise, we just use the ime target
+ return mInputMethodTarget;
+ }
+
void setLayoutNeeded() {
if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
mLayoutNeeded = true;
@@ -6684,4 +6733,50 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
Context getDisplayUiContext() {
return mDisplayPolicy.getSystemUiContext();
}
+
+ class RemoteInsetsControlTarget implements InsetsControlTarget {
+ private final IDisplayWindowInsetsController mRemoteInsetsController;
+
+ RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
+ mRemoteInsetsController = controller;
+ }
+
+ void notifyInsetsChanged() {
+ try {
+ mRemoteInsetsController.insetsChanged(
+ getInsetsStateController().getRawInsetsState());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void notifyInsetsControlChanged() {
+ final InsetsStateController stateController = getInsetsStateController();
+ try {
+ mRemoteInsetsController.insetsControlChanged(stateController.getRawInsetsState(),
+ stateController.getControlsForDispatch(this));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver inset state change", e);
+ }
+ }
+
+ @Override
+ public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.showInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+
+ @Override
+ public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ try {
+ mRemoteInsetsController.hideInsets(types, fromIme);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver showInsets", e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 05ede21472f2..fb97ecf8bbc4 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -69,7 +69,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
mShowImeRunner = () -> {
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
- mDisplayContent.mInputMethodTarget.showInsets(
+ mDisplayContent.mInputMethodControlTarget.showInsets(
WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 184e7d61c355..7b40f609aaf1 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -210,7 +210,7 @@ class InsetsSourceProvider {
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
}
- boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
+ boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) {
if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 152607470ed1..720493f4a466 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -91,6 +91,10 @@ class InsetsStateController {
return state;
}
+ InsetsState getRawInsetsState() {
+ return mState;
+ }
+
@Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
if (controlled == null) {
@@ -144,7 +148,7 @@ class InsetsStateController {
getImeSourceProvider().onPostInsetsDispatched();
}
- void onInsetsModified(WindowState windowState, InsetsState state) {
+ void onInsetsModified(InsetsControlTarget windowState, InsetsState state) {
boolean changed = false;
for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
@@ -296,6 +300,9 @@ class InsetsStateController {
void notifyInsetsChanged() {
mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
+ if (mDisplayContent.mRemoteInsetsControlTarget != null) {
+ mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
+ }
}
void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 399c5d3ae45f..eaa0ea72452a 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,8 +16,12 @@
package com.android.server.wm;
+import static com.android.server.wm.AnimationSpecProto.ROTATE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS;
+import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA;
+import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA;
import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -25,7 +29,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
+import android.animation.ArgbEvaluator;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -40,7 +46,9 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import com.android.internal.R;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.utils.RotationAnimationUtils;
import java.io.PrintWriter;
@@ -60,10 +68,10 @@ import java.io.PrintWriter;
* animation first rotate the new content into the old orientation to then be able to
* animate to the new orientation
*
- * <li> The exiting Blackframe: <p>
- * Because the change of orientation might change the width and height of the content (i.e
- * when rotating from portrait to landscape) we "crop" the new content using black frames
- * around the screenshot so the new content does not go beyond the screenshot's bounds
+ * <li> The Background color frame: <p>
+ * To have the animation seem more seamless, we add a color transitioning background behind the
+ * exiting and entering layouts. We compute the brightness of the start and end
+ * layouts and transition from the two brightness values as grayscale underneath the animation
*
* <li> The entering Blackframe: <p>
* The enter Blackframe is similar to the exit Blackframe but is only used when a custom
@@ -81,8 +89,6 @@ class ScreenRotationAnimation {
*/
private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
- private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
- private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
private final Context mContext;
private final DisplayContent mDisplayContent;
@@ -90,16 +96,18 @@ class ScreenRotationAnimation {
private final Transformation mRotateExitTransformation = new Transformation();
private final Transformation mRotateEnterTransformation = new Transformation();
// Complete transformations being applied.
- private final Transformation mExitTransformation = new Transformation();
private final Transformation mEnterTransformation = new Transformation();
- private final Matrix mFrameInitialMatrix = new Matrix();
private final Matrix mSnapshotInitialMatrix = new Matrix();
- private final Matrix mSnapshotFinalMatrix = new Matrix();
- private final Matrix mExitFrameFinalMatrix = new Matrix();
private final WindowManagerService mService;
+ /** Only used for custom animations and not screen rotation. */
private SurfaceControl mEnterBlackFrameLayer;
- private SurfaceControl mRotationLayer;
- private SurfaceControl mSurfaceControl;
+ /** This layer contains the actual screenshot that is to be faded out. */
+ private SurfaceControl mScreenshotLayer;
+ /**
+ * Only used for screen rotation and not custom animations. Layered behind all other layers
+ * to avoid showing any "empty" spots
+ */
+ private SurfaceControl mBackColorSurface;
private BlackFrame mEnteringBlackFrame;
private int mWidth, mHeight;
@@ -120,8 +128,11 @@ class ScreenRotationAnimation {
private boolean mFinishAnimReady;
private long mFinishAnimStartTime;
private boolean mForceDefaultOrientation;
- private BlackFrame mExitingBlackFrame;
private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
+ /** Intensity of light/whiteness of the layout before rotation occurs. */
+ private float mStartLuma;
+ /** Intensity of light/whiteness of the layout after rotation occurs. */
+ private float mEndLuma;
public ScreenRotationAnimation(Context context, DisplayContent displayContent,
boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -162,9 +173,15 @@ class ScreenRotationAnimation {
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
- mRotationLayer = displayContent.makeOverlay()
+ mBackColorSurface = displayContent.makeChildSurface(null)
+ .setName("BackColorSurface")
+ .setColorLayer()
+ .build();
+
+ mScreenshotLayer = displayContent.makeOverlay()
.setName("RotationLayer")
- .setContainerLayer()
+ .setBufferSize(mWidth, mHeight)
+ .setSecure(isSecure)
.build();
mEnterBlackFrameLayer = displayContent.makeOverlay()
@@ -172,26 +189,21 @@ class ScreenRotationAnimation {
.setContainerLayer()
.build();
- mSurfaceControl = mService.makeSurfaceBuilder(null)
- .setName("ScreenshotSurface")
- .setParent(mRotationLayer)
- .setBufferSize(mWidth, mHeight)
- .setSecure(isSecure)
- .build();
-
// In case display bounds change, screenshot buffer and surface may mismatch so set a
// scaling mode.
SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
- t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+ t2.setOverrideScalingMode(mScreenshotLayer, Surface.SCALING_MODE_SCALE_TO_WINDOW);
t2.apply(true /* sync */);
// Capture a screenshot into the surface we just created.
final int displayId = display.getDisplayId();
final Surface surface = mService.mSurfaceFactory.get();
- surface.copyFrom(mSurfaceControl);
+ surface.copyFrom(mScreenshotLayer);
SurfaceControl.ScreenshotGraphicBuffer gb =
mService.mDisplayManagerInternal.screenshot(displayId);
if (gb != null) {
+ mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(),
+ gb.getColorSpace());
try {
surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
gb.getColorSpace());
@@ -202,13 +214,15 @@ class ScreenRotationAnimation {
// screenshot surface we display it in also has FLAG_SECURE so that
// the user can not screenshot secure layers via the screenshot surface.
if (gb.containsSecureLayers()) {
- t.setSecure(mSurfaceControl, true);
+ t.setSecure(mScreenshotLayer, true);
}
- t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
- t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
- t.setAlpha(mSurfaceControl, 0);
- t.show(mRotationLayer);
- t.show(mSurfaceControl);
+ t.setLayer(mScreenshotLayer, SCREEN_FREEZE_LAYER_BASE);
+ t.reparent(mBackColorSurface, displayContent.getSurfaceControl());
+ t.setLayer(mBackColorSurface, -1);
+ t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
+ t.setAlpha(mBackColorSurface, 1);
+ t.show(mScreenshotLayer);
+ t.show(mBackColorSurface);
} else {
Slog.w(TAG, "Unable to take screenshot of display " + displayId);
}
@@ -218,32 +232,11 @@ class ScreenRotationAnimation {
}
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
- " FREEZE %s: CREATE", mSurfaceControl);
+ " FREEZE %s: CREATE", mScreenshotLayer);
setRotation(t, originalRotation);
t.apply();
}
- private static void createRotationMatrix(int rotation, int width, int height,
- Matrix outMatrix) {
- switch (rotation) {
- case Surface.ROTATION_0:
- outMatrix.reset();
- break;
- case Surface.ROTATION_90:
- outMatrix.setRotate(90, 0, 0);
- outMatrix.postTranslate(height, 0);
- break;
- case Surface.ROTATION_180:
- outMatrix.setRotate(180, 0, 0);
- outMatrix.postTranslate(width, height);
- break;
- case Surface.ROTATION_270:
- outMatrix.setRotate(270, 0, 0);
- outMatrix.postTranslate(0, width);
- break;
- }
- }
-
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(STARTED, mStarted);
@@ -252,11 +245,11 @@ class ScreenRotationAnimation {
}
boolean hasScreenshot() {
- return mSurfaceControl != null;
+ return mScreenshotLayer != null;
}
private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
- if (mRotationLayer == null) {
+ if (mScreenshotLayer == null) {
return;
}
matrix.getValues(mTmpFloats);
@@ -267,24 +260,19 @@ class ScreenRotationAnimation {
x -= mCurrentDisplayRect.left;
y -= mCurrentDisplayRect.top;
}
- t.setPosition(mRotationLayer, x, y);
- t.setMatrix(mRotationLayer,
+ t.setPosition(mScreenshotLayer, x, y);
+ t.setMatrix(mScreenshotLayer,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- t.setAlpha(mSurfaceControl, (float) 1.0);
- t.setAlpha(mRotationLayer, (float) 1.0);
- t.show(mRotationLayer);
+ t.setAlpha(mScreenshotLayer, (float) 1.0);
+ t.show(mScreenshotLayer);
}
public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
+ pw.print(prefix); pw.print("mSurface="); pw.print(mScreenshotLayer);
pw.print(" mWidth="); pw.print(mWidth);
pw.print(" mHeight="); pw.println(mHeight);
- pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.printTo(prefix + " ", pw);
- }
pw.print(prefix);
pw.print("mEnteringBlackFrame=");
pw.println(mEnteringBlackFrame);
@@ -303,20 +291,10 @@ class ScreenRotationAnimation {
pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mExitTransformation=");
- mExitTransformation.printShortString(pw); pw.println();
pw.print(prefix); pw.print("mEnterTransformation=");
mEnterTransformation.printShortString(pw); pw.println();
- pw.print(prefix); pw.print("mFrameInitialMatrix=");
- mFrameInitialMatrix.printShortString(pw);
- pw.println();
pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
- mSnapshotInitialMatrix.printShortString(pw);
- pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
- pw.println();
- pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
- mExitFrameFinalMatrix.printShortString(pw);
- pw.println();
+ mSnapshotInitialMatrix.printShortString(pw);pw.println();
pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
if (mForceDefaultOrientation) {
pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
@@ -331,7 +309,7 @@ class ScreenRotationAnimation {
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
- createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
+ RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
setRotationTransform(t, mSnapshotInitialMatrix);
}
@@ -341,7 +319,7 @@ class ScreenRotationAnimation {
*/
private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
@@ -354,89 +332,58 @@ class ScreenRotationAnimation {
// Figure out how the screen has moved from the original rotation.
int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
- mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_alpha);
final boolean customAnim;
if (exitAnim != 0 && enterAnim != 0) {
customAnim = true;
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
+ mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
+ R.anim.screen_rotate_alpha);
} else {
customAnim = false;
- switch (delta) {
+ switch (delta) { /* Counter-Clockwise Rotations */
case Surface.ROTATION_0:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_exit);
+ R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_0_enter);
+ R.anim.screen_rotate_0_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_exit);
+ R.anim.screen_rotate_plus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_plus_90_enter);
+ R.anim.screen_rotate_plus_90_enter);
break;
case Surface.ROTATION_180:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_exit);
+ R.anim.screen_rotate_180_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_180_enter);
+ R.anim.screen_rotate_180_enter);
break;
case Surface.ROTATION_270:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_exit);
+ R.anim.screen_rotate_minus_90_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.screen_rotate_minus_90_enter);
+ R.anim.screen_rotate_minus_90_enter);
break;
}
}
- // Initialize the animations. This is a hack, redefining what "parent"
- // means to allow supplying the last and next size. In this definition
- // "%p" is the original (let's call it "previous") size, and "%" is the
- // screen's current/new size.
- mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
- mAnimRunning = false;
- mFinishAnimReady = false;
- mFinishAnimStartTime = -1;
-
mRotateExitAnimation.restrictDuration(maxAnimationDuration);
mRotateExitAnimation.scaleCurrentDuration(animationScale);
+ mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
mRotateEnterAnimation.scaleCurrentDuration(animationScale);
- mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
- mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
- if (!customAnim && mExitingBlackFrame == null) {
- try {
- // Compute the transformation matrix that must be applied
- // the the black frame to make it stay in the initial position
- // before the new screen rotation. This is different than the
- // snapshot transformation because the snapshot is always based
- // of the native orientation of the screen, not the orientation
- // we were last in.
- createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
-
- final Rect outer;
- final Rect inner;
- if (mForceDefaultOrientation) {
- // Going from a smaller Display to a larger Display, add curtains to sides
- // or top and bottom. Going from a larger to smaller display will result in
- // no BlackSurfaces being constructed.
- outer = mCurrentDisplayRect;
- inner = mOriginalDisplayRect;
- } else {
- outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
- inner = new Rect(0, 0, mWidth, mHeight);
- }
- mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
- SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
- mRotationLayer);
- } catch (OutOfResourcesException e) {
- Slog.w(TAG, "Unable to allocate black surface", e);
- }
+ mAnimRunning = false;
+ mFinishAnimReady = false;
+ mFinishAnimStartTime = -1;
+
+ if (customAnim) {
+ mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
+ mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
}
if (customAnim && mEnteringBlackFrame == null) {
@@ -451,7 +398,12 @@ class ScreenRotationAnimation {
}
}
- mSurfaceRotationAnimationController.startAnimation();
+ if (customAnim) {
+ mSurfaceRotationAnimationController.startCustomAnimation();
+ } else {
+ mSurfaceRotationAnimationController.startScreenRotationAnimation();
+ }
+
return true;
}
@@ -460,11 +412,13 @@ class ScreenRotationAnimation {
*/
public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
- if (mSurfaceControl == null) {
+ if (mScreenshotLayer == null) {
// Can't do animation.
return false;
}
if (!mStarted) {
+ mEndLuma = RotationAnimationUtils.getLumaOfSurfaceControl(mDisplayContent.getDisplay(),
+ mDisplayContent.getWindowingLayer());
startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
exitAnim, enterAnim);
}
@@ -480,28 +434,28 @@ class ScreenRotationAnimation {
mSurfaceRotationAnimationController.cancel();
mSurfaceRotationAnimationController = null;
}
- if (mSurfaceControl != null) {
- ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mSurfaceControl);
- mSurfaceControl = null;
+
+ if (mScreenshotLayer != null) {
+ ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mScreenshotLayer);
SurfaceControl.Transaction t = mService.mTransactionFactory.get();
- if (mRotationLayer != null) {
- if (mRotationLayer.isValid()) {
- t.remove(mRotationLayer);
- }
- mRotationLayer = null;
+ if (mScreenshotLayer.isValid()) {
+ t.remove(mScreenshotLayer);
}
+ mScreenshotLayer = null;
+
if (mEnterBlackFrameLayer != null) {
if (mEnterBlackFrameLayer.isValid()) {
t.remove(mEnterBlackFrameLayer);
}
mEnterBlackFrameLayer = null;
}
+ if (mBackColorSurface != null) {
+ t.remove(mBackColorSurface);
+ mBackColorSurface = null;
+ }
t.apply();
}
- if (mExitingBlackFrame != null) {
- mExitingBlackFrame.kill();
- mExitingBlackFrame = null;
- }
+
if (mEnteringBlackFrame != null) {
mEnteringBlackFrame.kill();
mEnteringBlackFrame = null;
@@ -537,18 +491,28 @@ class ScreenRotationAnimation {
* Utility class that runs a {@link ScreenRotationAnimation} on the {@link
* SurfaceAnimationRunner}.
* <p>
- * The rotation animation is divided into the following hierarchy:
+ * The rotation animation supports both screen rotation and custom animations
+ *
+ * For custom animations:
+ * <ul>
+ * <li>
+ * The screenshot layer which has an added animation of it's alpha channel
+ * ("screen_rotate_alpha") and that will be applied along with the custom animation.
+ * </li>
+ * <li> A device layer that is animated with the provided custom animation </li>
+ * </ul>
+ *
+ * For screen rotation:
* <ul>
- * <li> A first rotation layer, containing the blackframes. This layer is animated by the
- * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
- * <ul>
- * <li> A child layer containing the screenshot on which is added an animation of it's
- * alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
- * </ul>
- * <li> A second rotation layer used when custom animations are passed in
+ * <li> A rotation layer that is both rotated and faded out during a single animation </li>
+ * <li> A device layer that is both rotated and faded in during a single animation </li>
+ * <li> A background color layer that transitions colors behind the first two layers </li>
+ * </ul>
+ *
* {@link ScreenRotationAnimation#startAnimation(
* SurfaceControl.Transaction, long, float, int, int, int, int)}.
* </ul>
+ *
* <p>
* Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
* this three {@link SurfaceControl}s which then delegates the animation to the
@@ -556,22 +520,35 @@ class ScreenRotationAnimation {
*/
class SurfaceRotationAnimationController {
private SurfaceAnimator mDisplayAnimator;
- private SurfaceAnimator mEnterBlackFrameAnimator;
private SurfaceAnimator mScreenshotRotationAnimator;
private SurfaceAnimator mRotateScreenAnimator;
+ private SurfaceAnimator mEnterBlackFrameAnimator;
+
+ void startCustomAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mRotateScreenAnimator = startScreenshotAlphaAnimation();
+ mDisplayAnimator = startDisplayRotation();
+ if (mEnteringBlackFrame != null) {
+ mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ }
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
+ }
+ }
/**
* Start the rotation animation of the display and the screenshot on the
* {@link SurfaceAnimationRunner}.
*/
- void startAnimation() {
- mRotateScreenAnimator = startScreenshotAlphaAnimation();
- mDisplayAnimator = startDisplayRotation();
- if (mExitingBlackFrame != null) {
+ void startScreenRotationAnimation() {
+ try {
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ mDisplayAnimator = startDisplayRotation();
mScreenshotRotationAnimator = startScreenshotRotationAnimation();
- }
- if (mEnteringBlackFrame != null) {
- mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+ startColorAnimation();
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
}
@@ -596,8 +573,8 @@ class ScreenRotationAnimation {
private SurfaceAnimator startScreenshotAlphaAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mSurfaceControl)
- .setAnimationLeashParent(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
+ .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.setWidth(mWidth)
.setHeight(mHeight)
.build(),
@@ -616,13 +593,67 @@ class ScreenRotationAnimation {
private SurfaceAnimator startScreenshotRotationAnimation() {
return startAnimation(initializeBuilder()
- .setSurfaceControl(mRotationLayer)
+ .setSurfaceControl(mScreenshotLayer)
.setAnimationLeashParent(mDisplayContent.getOverlayLayer())
.build(),
createWindowAnimationSpec(mRotateExitAnimation),
this::onAnimationEnd);
}
+
+ /**
+ * Applies the color change from {@link #mStartLuma} to {@link #mEndLuma} as a
+ * grayscale color
+ */
+ private void startColorAnimation() {
+ int colorTransitionMs = mContext.getResources().getInteger(
+ R.integer.config_screen_rotation_color_transition);
+ final SurfaceAnimationRunner runner = mService.mSurfaceAnimationRunner;
+ final float[] rgbTmpFloat = new float[3];
+ final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
+ final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
+ final long duration = colorTransitionMs * (long) mService.getCurrentAnimatorScale();
+ final ArgbEvaluator va = ArgbEvaluator.getInstance();
+ runner.startAnimation(
+ new LocalAnimationAdapter.AnimationSpec() {
+ @Override
+ public long getDuration() {
+ return duration;
+ }
+
+ @Override
+ public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+ long currentPlayTime) {
+ float fraction = (float)currentPlayTime / (float)getDuration();
+ int color = (Integer) va.evaluate(fraction, startColor, endColor);
+ Color middleColor = Color.valueOf(color);
+ rgbTmpFloat[0] = middleColor.red();
+ rgbTmpFloat[1] = middleColor.green();
+ rgbTmpFloat[2] = middleColor.blue();
+ if (leash.isValid()) {
+ t.setColor(leash, rgbTmpFloat);
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "startLuma=" + mStartLuma
+ + " endLuma=" + mEndLuma
+ + " durationMs=" + colorTransitionMs);
+ }
+
+ @Override
+ public void dumpDebugInner(ProtoOutputStream proto) {
+ final long token = proto.start(ROTATE);
+ proto.write(START_LUMA, mStartLuma);
+ proto.write(END_LUMA, mEndLuma);
+ proto.write(DURATION_MS, colorTransitionMs);
+ proto.end(token);
+ }
+ },
+ mBackColorSurface, mDisplayContent.getPendingTransaction(), null);
+ }
+
private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
@@ -646,7 +677,6 @@ class ScreenRotationAnimation {
LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
animationSpec, mService.mSurfaceAnimationRunner);
-
animator.startAnimation(mDisplayContent.getPendingTransaction(),
localAnimationAdapter, false);
return animator;
@@ -692,7 +722,6 @@ class ScreenRotationAnimation {
if (mEnterBlackFrameAnimator != null) {
mEnterBlackFrameAnimator.cancelAnimation();
}
-
if (mScreenshotRotationAnimator != null) {
mScreenshotRotationAnimator.cancelAnimation();
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 50cea2ed52cc..5633b6be87b9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -78,6 +78,10 @@ class SurfaceAnimationRunner {
@GuardedBy("mLock")
private boolean mAnimationStartDeferred;
+ /**
+ * There should only ever be one instance of this class. Usual spot for it is with
+ * {@link WindowManagerService}
+ */
SurfaceAnimationRunner(Supplier<Transaction> transactionFactory,
PowerManagerInternal powerManagerInternal) {
this(null /* callbackProvider */, null /* animatorFactory */,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 223e9b9e3df2..74fdba1cd13e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -205,6 +205,7 @@ import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDisplayFoldListener;
+import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowListener;
import android.view.IDisplayWindowRotationController;
import android.view.IDockedStackListener;
@@ -2768,6 +2769,7 @@ public class WindowManagerService extends IWindowManager.Stub
true /* includingParents */);
}
}
+ syncInputTransactions();
}
/**
@@ -3727,6 +3729,48 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void setDisplayWindowInsetsController(
+ int displayId, IDisplayWindowInsetsController insetsController) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return;
+ }
+ dc.setRemoteInsetsController(insetsController);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void modifyDisplayWindowInsets(int displayId, InsetsState state) {
+ if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null || dc.mRemoteInsetsControlTarget == null) {
+ return;
+ }
+ dc.getInsetsStateController().onInsetsModified(
+ dc.mRemoteInsetsControlTarget, state);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
synchronized (mGlobalLock) {
@@ -7314,7 +7358,8 @@ public class WindowManagerService extends IWindowManager.Stub
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
- dc.mInputMethodTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(),
+ true /* fromIme */);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4e768da18041..96bc8e963b38 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -792,8 +792,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
- mRequestedInsetsState =
- getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this);
+ mRequestedInsetsState = new InsetsState(
+ getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this),
+ true /* copySources */);
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
new file mode 100644
index 000000000000..94f66768d5ef
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -0,0 +1,97 @@
+/*
+ * 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.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+
+/** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
+public class RotationAnimationUtils {
+
+ /**
+ * Converts the provided {@link GraphicBuffer} and converts it to a bitmap to then sample the
+ * luminance at the borders of the bitmap
+ * @return the average luminance of all the pixels at the borders of the bitmap
+ */
+ public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+ Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
+ if (hwBitmap == null) {
+ return 0;
+ }
+
+ Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
+ float totalLuma = 0;
+ int height = swaBitmap.getHeight();
+ int width = swaBitmap.getWidth();
+ int i;
+ for (i = 0; i < width; i++) {
+ totalLuma += swaBitmap.getColor(i, 0).luminance();
+ totalLuma += swaBitmap.getColor(i, height - 1).luminance();
+ }
+ for (i = 0; i < height; i++) {
+ totalLuma += swaBitmap.getColor(0, i).luminance();
+ totalLuma += swaBitmap.getColor(width - 1, i).luminance();
+ }
+ return totalLuma / (2 * width + 2 * height);
+ }
+
+ /**
+ * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
+ * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace)
+ */
+ public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
+ if (surfaceControl == null) {
+ return 0;
+ }
+
+ Point size = new Point();
+ display.getSize(size);
+ Rect crop = new Rect(0, 0, size.x, size.y);
+ SurfaceControl.ScreenshotGraphicBuffer buffer =
+ SurfaceControl.captureLayers(surfaceControl, crop, 1);
+ return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(),
+ buffer.getColorSpace());
+ }
+
+ public static void createRotationMatrix(int rotation, int width, int height, Matrix outMatrix) {
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ outMatrix.reset();
+ break;
+ case Surface.ROTATION_90:
+ outMatrix.setRotate(90, 0, 0);
+ outMatrix.postTranslate(height, 0);
+ break;
+ case Surface.ROTATION_180:
+ outMatrix.setRotate(180, 0, 0);
+ outMatrix.postTranslate(width, height);
+ break;
+ case Surface.ROTATION_270:
+ outMatrix.setRotate(270, 0, 0);
+ outMatrix.postTranslate(0, width);
+ break;
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 5a1d552bf325..8641059aebd5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -64,4 +64,8 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
}
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {}
+
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 13246ba9e587..2a08f5c2de12 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8607,6 +8607,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public boolean isOrganizationOwnedDeviceWithManagedProfile() {
+ if (!mHasFeature) {
+ return false;
+ }
+ enforceManageUsers();
+
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ for (UserInfo ui : mUserManager.getUsers()) {
+ if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ }
+
+ @Override
public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
ensureCallerIdentityMatchesIfNotSystem(packageName, pid, uid);
@@ -14584,8 +14602,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
for (int i = 0; i < users.length; i++) {
final ComponentName componentName = getProfileOwner(users[i]);
if (componentName != null) {
- admins.add(getActiveAdminForCallerLocked(
- componentName, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(componentName, users[i]);
+ if (admin != null) {
+ admins.add(admin);
+ }
}
}
return admins;
diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
new file mode 100644
index 000000000000..4cbdbd178944
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Unit tests for {@link LocationRequestStatistics}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class LocationRequestStatisticsTest {
+
+ /**
+ * Check adding and removing requests & strings
+ */
+ @Test
+ public void testRequestSummary() {
+ LocationRequestStatistics.RequestSummary summary =
+ new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps", 1000);
+ StringWriter stringWriter = new StringWriter();
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234);
+ assertThat(stringWriter.toString()).startsWith("At");
+
+ StringWriter stringWriterRemove = new StringWriter();
+ summary = new LocationRequestStatistics.RequestSummary(
+ "com.example", "gps",
+ LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
+ summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345);
+ assertThat(stringWriterRemove.toString()).contains("-");
+ }
+
+ /**
+ * Check summary list size capping
+ */
+ @Test
+ public void testSummaryList() {
+ LocationRequestStatistics statistics = new LocationRequestStatistics();
+ statistics.history.addRequest("com.example", "gps", 1000);
+ assertThat(statistics.history.mList.size()).isEqualTo(1);
+ // Try (not) to overflow
+ for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
+ statistics.history.addRequest("com.example", "gps", 1000);
+ }
+ assertThat(statistics.history.mList.size()).isEqualTo(
+ LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index f3c76b609c25..8871348d0027 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.PendingHostUpdate;
import android.content.BroadcastReceiver;
@@ -80,6 +81,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
super.setUp();
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+ LocalServices.removeServiceForTest(AppWidgetManagerInternal.class);
mTestContext = new TestContext();
mPkgName = mTestContext.getOpPackageName();
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
new file mode 100644
index 000000000000..d0767ccb6f87
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+
+class ApplicationInfoBuilder {
+ private boolean mIsDebuggable;
+ private int mTargetSdk;
+ private String mPackageName;
+
+ private ApplicationInfoBuilder() {
+ mTargetSdk = -1;
+ }
+
+ static ApplicationInfoBuilder create() {
+ return new ApplicationInfoBuilder();
+ }
+
+ ApplicationInfoBuilder withTargetSdk(int targetSdk) {
+ mTargetSdk = targetSdk;
+ return this;
+ }
+
+ ApplicationInfoBuilder debuggable() {
+ mIsDebuggable = true;
+ return this;
+ }
+
+ ApplicationInfoBuilder withPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ ApplicationInfo build() {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ if (mIsDebuggable) {
+ applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
+ }
+ applicationInfo.packageName = mPackageName;
+ applicationInfo.targetSdkVersion = mTargetSdk;
+ return applicationInfo;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
new file mode 100644
index 000000000000..328c71dbc7db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.compat;
+
+import android.content.Context;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class for creating a CompatConfig.
+ */
+class CompatConfigBuilder {
+ private ArrayList<CompatChange> mChanges;
+ private AndroidBuildClassifier mBuildClassifier;
+ private Context mContext;
+
+ private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) {
+ mChanges = new ArrayList<>();
+ mBuildClassifier = buildClassifier;
+ mContext = context;
+ }
+
+ static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) {
+ return new CompatConfigBuilder(buildClassifier, context);
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", sdk, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
+ mChanges.add(new CompatChange(id, name, sdk, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
+ String description) {
+ mChanges.add(new CompatChange(id, "", sdk, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, false, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, false, ""));
+ return this;
+ }
+ CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, false, description));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithId(long id) {
+ mChanges.add(new CompatChange(id, "", -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
+ mChanges.add(new CompatChange(id, name, -1, true, ""));
+ return this;
+ }
+
+ CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
+ mChanges.add(new CompatChange(id, "", -1, true, description));
+ return this;
+ }
+
+ CompatConfig build() {
+ CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
+ for (CompatChange change : mChanges) {
+ config.addChange(change);
+ }
+ return config;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index cb99c118a407..407f67e2fd8e 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,12 +18,25 @@ package com.android.server.compat;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.compat.AndroidBuildClassifier;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.File;
import java.io.FileOutputStream;
@@ -34,12 +47,12 @@ import java.util.UUID;
@RunWith(AndroidJUnit4.class)
public class CompatConfigTest {
- private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
- ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = pName;
- ai.targetSdkVersion = targetSdkVersion;
- return ai;
- }
+ @Mock
+ private Context mContext;
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
private File createTempDir() {
String base = System.getProperty("java.io.tmpdir");
@@ -54,112 +67,206 @@ public class CompatConfigTest {
os.close();
}
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ }
+
+ @Test
+ public void testUnknownChangeEnabled() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isTrue();
+ }
+
@Test
- public void testUnknownChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ public void testDisabledChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
+ .isFalse();
}
@Test
- public void testDisabledChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ public void testTargetSdkChangeDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(2).build()))
+ .isFalse();
}
@Test
- public void testTargetSdkChangeDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ public void testTargetSdkChangeEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
}
@Test
- public void testTargetSdkChangeEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, ""));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ public void testDisabledOverrideTargetSdkChange() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addTargetSdkDisabledChangeWithId(2, 1234L)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse();
}
@Test
- public void testDisabledOverrideTargetSdkChange() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
+ public void testGetDisabledChanges() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addEnabledChangeWithId(2345L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(
+ ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L);
}
@Test
- public void testGetDisabledChanges() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null));
- pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
+ public void testGetDisabledChangesSorted() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addDisabledChangeWithId(123L)
+ .addDisabledChangeWithId(12L)
+ .build();
+
+ assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build()))
+ .asList().containsExactly(12L, 123L, 1234L);
}
@Test
- public void testGetDisabledChangesSorted() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null));
- pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null));
- assertThat(pc.getDisabledChanges(
- makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
+ public void testPackageOverrideEnabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isFalse();
}
@Test
- public void testPackageOverrideEnabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled
- pc.addOverride(1234L, "com.some.package", true);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
+ public void testPackageOverrideDisabled() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testPackageOverrideDisabled() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPackageOverrideUnknownPackage() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+
+ compatConfig.addOverride(1234L, "com.some.package", false);
+
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
+ .withPackageName("com.other.package").build())).isTrue();
}
@Test
- public void testPackageOverrideUnknownPackage() {
- CompatConfig pc = new CompatConfig();
- pc.addOverride(1234L, "com.some.package", false);
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ public void testPreventAddOverride() throws Exception {
+ final long changeId = 1234L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ assertThrows(SecurityException.class,
+ () -> compatConfig.addOverride(1234L, "com.some.package", true)
+ );
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
}
@Test
- public void testPackageOverrideUnknownChange() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ public void testPreventRemoveOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+ // Assume the override was allowed to be added.
+ compatConfig.addOverride(1234L, "com.some.package", true);
+
+ // Validator allows turning on the change.
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+
+ // Reject all override attempts.
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+ // Try to turn off change, but validator prevents it.
+ assertThrows(SecurityException.class,
+ () -> compatConfig.removeOverride(1234L, "com.some.package"));
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
- public void testRemovePackageOverride() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addOverride(1234L, "com.some.package", false);
- pc.removeOverride(1234L, "com.some.package");
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ public void testRemovePackageOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+
+ assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+ compatConfig.removeOverride(1234L, "com.some.package");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
- public void testLookupChangeId() {
- CompatConfig pc = new CompatConfig();
- pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
- pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null));
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ public void testLookupChangeId() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
+ .addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE")
+ .build();
+
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
}
@Test
- public void testLookupChangeIdNotPresent() {
- CompatConfig pc = new CompatConfig();
- assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
+ public void testLookupChangeIdNotPresent() throws Exception {
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
}
@Test
@@ -172,14 +279,17 @@ public class CompatConfigTest {
File dir = createTempDir();
writeToFile(dir, "platform_compat_config.xml", configXml);
-
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
@Test
@@ -195,15 +305,16 @@ public class CompatConfigTest {
File dir = createTempDir();
writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
-
- CompatConfig pc = new CompatConfig();
- pc.initConfigFromLib(dir);
-
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
- assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
- assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
- assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
}
-
-
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
new file mode 100644
index 000000000000..793296e88169
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java
@@ -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 com.android.server.compat;
+
+import android.compat.Compatibility;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class CompatibilityChangeConfigBuilder {
+ private Set<Long> mEnabled;
+ private Set<Long> mDisabled;
+
+ private CompatibilityChangeConfigBuilder() {
+ mEnabled = new HashSet<>();
+ mDisabled = new HashSet<>();
+ }
+
+ static CompatibilityChangeConfigBuilder create() {
+ return new CompatibilityChangeConfigBuilder();
+ }
+
+ CompatibilityChangeConfigBuilder enable(Long id) {
+ mEnabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfigBuilder disable(Long id) {
+ mDisabled.add(id);
+ return this;
+ }
+
+ CompatibilityChangeConfig build() {
+ return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
new file mode 100644
index 000000000000..ecd07bdc4544
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
+import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.IOverrideValidator;
+import com.android.internal.compat.OverrideAllowedState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class OverrideValidatorImplTest {
+ private static final String PACKAGE_NAME = "my.package";
+ private static final int TARGET_SDK = 10;
+ private static final int TARGET_SDK_BEFORE = 9;
+ private static final int TARGET_SDK_AFTER = 11;
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ Context mContext;
+
+ private AndroidBuildClassifier debuggableBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier betaBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(false);
+ return buildClassifier;
+ }
+
+ private AndroidBuildClassifier finalBuild() {
+ AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
+ when(buildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(buildClassifier.isFinalBuild()).thenReturn(true);
+ return buildClassifier;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .debuggable()
+ .withTargetSdk(TARGET_SDK)
+ .withPackageName(PACKAGE_NAME).build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
+ TARGET_SDK_BEFORE));
+ assertThat(stateTargetSdkEqualChange).isEqualTo(
+ new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addEnabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addDisabledChangeWithId(1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable().build());
+
+ OverrideAllowedState allowedState =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+
+ assertThat(allowedState)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ }
+
+ @Test
+ public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride()
+ throws Exception {
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
+ .addTargetSdkChangeWithId(TARGET_SDK, 2)
+ .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+ .addEnabledChangeWithId(4)
+ .addDisabledChangeWithId(5).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withTargetSdk(TARGET_SDK).build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkEqualChange =
+ overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
+ OverrideAllowedState stateTargetSdkAfterChange =
+ overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+ OverrideAllowedState stateEnabledChange =
+ overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
+ OverrideAllowedState stateDisabledChange =
+ overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+
+ assertThat(stateTargetSdkLessChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkEqualChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateTargetSdkAfterChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateEnabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ assertThat(stateDisabledChange)
+ .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index c406876c5cee..ce5d6d9be770 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -26,21 +26,20 @@ import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.testng.Assert.assertThrows;
-import android.compat.Compatibility;
import android.content.Context;
import android.content.pm.PackageManager;
-import com.android.internal.compat.CompatibilityChangeConfig;
+import androidx.test.runner.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
+import com.android.internal.compat.AndroidBuildClassifier;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.MockitoAnnotations;
-@RunWith(MockitoJUnitRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PlatformCompatTest {
private static final String PACKAGE_NAME = "my.package";
@@ -50,84 +49,77 @@ public class PlatformCompatTest {
private PackageManager mPackageManager;
@Mock
CompatChange.ChangeListener mListener1, mListener2;
-
+ PlatformCompat mPlatformCompat;
+ CompatConfig mCompatConfig;
+ @Mock
+ private AndroidBuildClassifier mBuildClassifier;
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
new PackageManager.NameNotFoundException());
- CompatConfig.get().clearChanges();
+ mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ // Assume userdebug/eng non-final build
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(false);
}
@Test
- public void testRegisterListenerToSameIdThrows() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
+ public void testRegisterListenerToSameIdThrows() throws Exception {
// Registering a listener to change 1 is successful.
- pc.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(1, mListener1);
// Registering a listener to change 2 is successful.
- pc.registerListener(2, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
// Trying to register another listener to change id 1 fails.
- assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
+ assertThrows(IllegalStateException.class,
+ () -> mPlatformCompat.registerListener(1, mListener1));
}
@Test
- public void testRegisterListenerReturn() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ public void testRegisterListenerReturn() throws Exception {
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
// Change id 1 is known (added in setOverrides).
- assertThat(pc.registerListener(1, mListener1)).isTrue();
+ assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue();
// Change 2 is unknown.
- assertThat(pc.registerListener(2, mListener1)).isFalse();
+ assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse();
}
@Test
- public void testListenerCalledOnSetOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnSetOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerNotCalledOnWrongPackage() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
+ public void testListenerNotCalledOnWrongPackage() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, never()).onCompatChange("other.package");
}
@Test
- public void testListenerCalledOnSetOverridesTwoListeners() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -136,11 +128,10 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -148,31 +139,23 @@ public class PlatformCompatTest {
}
@Test
- public void testListenerCalledOnSetOverridesForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener1);
+ public void testListenerCalledOnSetOverridesForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener1);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnSetOverridesTwoListenersForTest() {
- PlatformCompat pc = new PlatformCompat(mContext);
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
- final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
-
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -181,10 +164,10 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.registerListener(2, mListener2);
- pc.setOverridesForTest(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled)),
+ mPlatformCompat.registerListener(2, mListener2);
+
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
@@ -192,15 +175,12 @@ public class PlatformCompatTest {
}
@Test
- public void testListenerCalledOnClearOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -208,21 +188,18 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverridesMultipleOverrides() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
+ public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
@@ -230,21 +207,18 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverrides(PACKAGE_NAME);
+ mPlatformCompat.clearOverrides(PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideExists() {
- PlatformCompat pc = new PlatformCompat(mContext);
+ public void testListenerCalledOnClearOverrideExists() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
+ mPlatformCompat.registerListener(2, mListener2);
- pc.registerListener(1, mListener1);
- pc.registerListener(2, mListener2);
-
- pc.setOverrides(
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ mPlatformCompat.setOverrides(
+ CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
@@ -252,21 +226,17 @@ public class PlatformCompatTest {
reset(mListener1);
reset(mListener2);
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
}
@Test
- public void testListenerCalledOnClearOverrideDoesntExist() {
- PlatformCompat pc = new PlatformCompat(mContext);
-
- pc.registerListener(1, mListener1);
+ public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
+ mPlatformCompat.registerListener(1, mListener1);
- pc.clearOverride(1, PACKAGE_NAME);
+ mPlatformCompat.clearOverride(1, PACKAGE_NAME);
// Listener not called when a non existing override is removed.
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
}
-
-
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a16e14f61a66..175c7565a005 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3636,6 +3636,29 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
+ public void testIsOrganizationOwnedDevice() throws Exception {
+ setupProfileOwner();
+ // Set up the user manager to return correct user info
+ UserInfo managedProfileUserInfo = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
+ "managed profile",
+ UserInfo.FLAG_MANAGED_PROFILE);
+ when(getServices().userManager.getUsers())
+ .thenReturn(Arrays.asList(managedProfileUserInfo));
+
+ // Any caller without the MANAGE_USERS permission should get a security exception.
+ assertExpectException(SecurityException.class, null, () ->
+ dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ // But when the right permission is granted, this should succeed.
+ mContext.permissions.add(android.Manifest.permission.MANAGE_USERS);
+ assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+
+ // A random caller from another user should also be able to get the right result.
+ mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+ assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile());
+ }
+
public void testSetTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index ebca240819e8..25d077823a3f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -78,7 +78,7 @@ public class DisplayModeDirectorTest {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/60,
+ assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60,
new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
displayId));
@@ -105,7 +105,7 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
assertEquals(
new DisplayModeDirector.DesiredDisplayModeSpecs(
- /*defaultModeId=*/minFps + i,
+ /*baseModeId=*/minFps + i,
new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)),
director.getDesiredDisplayModeSpecs(displayId));
}
@@ -126,7 +126,7 @@ public class DisplayModeDirectorTest {
votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
DisplayModeDirector.Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/70,
+ assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70,
new DisplayModeDirector.RefreshRateRange(70, 80)),
director.getDesiredDisplayModeSpecs(displayId));
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
new file mode 100644
index 000000000000..742952e056bc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.parser;
+
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
+import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class RuleIndexingControllerTest {
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ddd")
+ .setAppCertificate("777")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysInFirstAndLastBlock() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("bbb")
+ .setAppCertificate("999")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 200),
+ new RuleIndexRange(800, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_keysMatchWithValues() throws IOException {
+ InputStream inputStream = obtainDefaultIndexingMapForTest();
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(200, 300),
+ new RuleIndexRange(700, 800),
+ new RuleIndexRange(900, 945));
+ }
+
+ @Test
+ public void verifyIndexRangeSearchIsCorrect_noIndexesAvailable() throws IOException {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+ RuleIndexingController indexingController = new RuleIndexingController(inputStream);
+
+ AppInstallMetadata appInstallMetadata =
+ new AppInstallMetadata.Builder()
+ .setPackageName("ccc")
+ .setAppCertificate("444")
+ .build();
+
+ List<RuleIndexRange> resultingIndexes =
+ indexingController.identifyRulesToEvaluate(appInstallMetadata);
+
+ assertThat(resultingIndexes)
+ .containsExactly(
+ new RuleIndexRange(100, 500),
+ new RuleIndexRange(500, 900),
+ new RuleIndexRange(900, 945));
+ }
+
+ private static InputStream obtainDefaultIndexingMapForTest() {
+ byte[] stringBytes =
+ getBytes(
+ getKeyValueString(START_INDEXING_KEY, 100)
+ + getKeyValueString("ccc", 200)
+ + getKeyValueString("eee", 300)
+ + getKeyValueString("hhh", 400)
+ + getKeyValueString(END_INDEXING_KEY, 500)
+ + getKeyValueString(START_INDEXING_KEY, 500)
+ + getKeyValueString("111", 600)
+ + getKeyValueString("444", 700)
+ + getKeyValueString("888", 800)
+ + getKeyValueString(END_INDEXING_KEY, 900)
+ + getKeyValueString(START_INDEXING_KEY, 900)
+ + getKeyValueString(END_INDEXING_KEY, 945));
+ ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+ rule.put(stringBytes);
+ return new ByteArrayInputStream(rule.array());
+ }
+
+ private static String getKeyValueString(String key, int value) {
+ String isNotHashed = "0";
+ return isNotHashed
+ + getBits(key.length(), VALUE_SIZE_BITS)
+ + getValueBits(key)
+ + getBits(value, /* numOfBits= */ 32);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 28e6830515f0..c7dbad83e384 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -1273,11 +1273,11 @@ public class NetworkPolicyManagerServiceTest {
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
stats.clear();
- stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
@@ -1301,9 +1301,9 @@ public class NetworkPolicyManagerServiceTest {
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
stats.clear();
- stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0);
- stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
new file mode 100644
index 000000000000..7666ab9ed5ae
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ServiceManager;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySavingStats;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.power.Notifier}
+ */
+public class NotifierTest {
+ private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+ private static final int USER_ID = 0;
+
+ @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
+ @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock private Notifier mNotifierMock;
+ @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+ @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
+ @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
+ @Mock private BatteryStatsImpl mBatteryStats;
+ @Mock private Vibrator mVibrator;
+ @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+
+ private PowerManagerService mService;
+ private Context mContextSpy;
+ private Resources mResourcesSpy;
+ private TestLooper mTestLooper = new TestLooper();
+ private Notifier mNotifier;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
+
+ mContextSpy = spy(new TestableContext(InstrumentationRegistry.getContext()));
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+ when(mContextSpy.getSystemService(Vibrator.class)).thenReturn(mVibrator);
+
+ mService = new PowerManagerService(mContextSpy, mInjector);
+ }
+
+ @Test
+ public void testVibrateEnabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateDisabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabled
+ enableChargingVibration(false);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateEnabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateDisabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabeld
+ enableChargingVibration(false);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testVibrateEnabled_dndOn() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled but dnd is on
+ enableChargingVibration(true);
+ enableChargingFeedback(
+ /* chargingFeedbackEnabled */ true,
+ /* dndOn */ true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any());
+ }
+
+ @Test
+ public void testWirelessAnimationEnabled() {
+ // GIVEN the wireless charging animation is enabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(true);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the charging animation is triggered
+ verify(mStatusBarManagerInternal, times(1)).showChargingAnimation(5);
+ }
+
+ @Test
+ public void testWirelessAnimationDisabled() {
+ // GIVEN the wireless charging animation is disabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(false);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+
+ // THEN the charging animation never gets called
+ verify(mStatusBarManagerInternal, never()).showChargingAnimation(anyInt());
+ }
+
+ private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
+ @Override
+ Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+ SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
+ return mNotifierMock;
+ }
+
+ @Override
+ SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+ return super.createSuspendBlocker(service, name);
+ }
+
+ @Override
+ BatterySaverPolicy createBatterySaverPolicy(
+ Object lock, Context context, BatterySavingStats batterySavingStats) {
+ return mBatterySaverPolicyMock;
+ }
+
+ @Override
+ PowerManagerService.NativeWrapper createNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ WirelessChargerDetector createWirelessChargerDetector(
+ SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
+ return mWirelessChargerDetectorMock;
+ }
+
+ @Override
+ AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
+ return mAmbientDisplayConfigurationMock;
+ }
+
+ @Override
+ InattentiveSleepWarningController createInattentiveSleepWarningController() {
+ return mInattentiveSleepWarningControllerMock;
+ }
+
+ @Override
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+ };
+
+ private void enableChargingFeedback(boolean chargingFeedbackEnabled, boolean dndOn) {
+ // enable/disable charging feedback
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_SOUNDS_ENABLED,
+ chargingFeedbackEnabled ? 1 : 0,
+ USER_ID);
+
+ // toggle on/off dnd
+ Settings.Global.putInt(
+ mContextSpy.getContentResolver(),
+ Settings.Global.ZEN_MODE,
+ dndOn ? Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ : Settings.Global.ZEN_MODE_OFF);
+ }
+
+ private void enableChargingVibration(boolean enable) {
+ enableChargingFeedback(true, false);
+
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_VIBRATION_ENABLED,
+ enable ? 1 : 0,
+ USER_ID);
+ }
+
+ private void createNotifier() {
+ mNotifier = new Notifier(
+ mTestLooper.getLooper(),
+ mContextSpy,
+ IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME)),
+ mInjector.createSuspendBlocker(mService, "testBlocker"),
+ null);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 71b568cc06c5..ae5369204428 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -37,7 +37,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index ca6fd08092df..aaf9799de777 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -30,7 +30,7 @@ import android.content.Intent;
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
index 239d413c12d2..f1e9191ddb4f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyTest.java
@@ -18,7 +18,7 @@ package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
-import android.util.TimestampedValue;
+import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index 574517a00f6f..71390dbbe4a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -40,7 +40,7 @@ import org.mockito.MockitoAnnotations;
* Tests for the {@link ActivityStack} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:AnimatingActivityRegistryTest
+ * atest WmTests:AnimatingActivityRegistryTest
*/
@SmallTest
@Presubmit
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 1311889d5605..f6213bd94ddd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -42,7 +42,7 @@ import org.junit.runner.RunWith;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:AppTransitionControllerTest
+ * atest WmTests:AppTransitionControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 0ad0f95f64c1..1dda535cfb95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -60,7 +60,7 @@ import org.junit.runner.RunWith;
* appropriately.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:BoundsAnimationControllerTests
+ * atest WmTests:BoundsAnimationControllerTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 0aa6961d20b3..e8f7849ef96a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:DimmerTests
+ * atest WmTests:DimmerTests
*/
@Presubmit
@RunWith(WindowTestRunner.class)
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 73dd2df27e95..f2ba97c269d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -86,6 +88,7 @@ import android.view.IWindowManager;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewRootImpl;
+import android.view.WindowManager;
import android.view.test.InsetsModeSession;
import androidx.test.filters.SmallTest;
@@ -561,8 +564,7 @@ public class DisplayContentTests extends WindowTestsBase {
final DisplayContent dc = createNewDisplay();
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
}
@@ -829,8 +831,7 @@ public class DisplayContentTests extends WindowTestsBase {
win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
dc.updateSystemGestureExclusion();
@@ -866,8 +867,7 @@ public class DisplayContentTests extends WindowTestsBase {
win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -898,8 +898,7 @@ public class DisplayContentTests extends WindowTestsBase {
win2.getAttrs().height = 10;
win2.setSystemGestureExclusion(Collections.emptyList());
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
win2.setHasSurface(true);
@@ -922,8 +921,7 @@ public class DisplayContentTests extends WindowTestsBase {
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
win.mActivityRecord.mTargetSdk = P;
- dc.setLayoutNeeded();
- dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ performLayout(dc);
win.setHasSurface(true);
@@ -935,6 +933,22 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testRequestResizeForEmptyFrames() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.setRequestedSize(mDisplayContent.mBaseDisplayWidth, 0 /* height */);
+ win.mAttrs.width = win.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ win.mAttrs.gravity = Gravity.CENTER;
+ performLayout(mDisplayContent);
+
+ // The frame is empty because the requested height is zero.
+ assertTrue(win.getFrameLw().isEmpty());
+ // The window should be scheduled to resize then the client may report a new non-empty size.
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).contains(win);
+ }
+
+ @Test
public void testOrientationChangeLogging() {
MetricsLogger mockLogger = mock(MetricsLogger.class);
Configuration oldConfig = new Configuration();
@@ -1011,6 +1025,11 @@ public class DisplayContentTests extends WindowTestsBase {
mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
}
+ private void performLayout(DisplayContent dc) {
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+ }
+
/**
* Create DisplayContent that does not update display base/initial values from device to keep
* the values set by test.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 112479b3b9a0..1a575962b961 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -61,7 +61,7 @@ import org.mockito.MockitoAnnotations;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:RemoteAnimationControllerTest
+ * atest WmTests:RemoteAnimationControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index e0112809b22b..bac2bcae30de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -60,7 +60,7 @@ import java.util.concurrent.CountDownLatch;
* Test class for {@link SurfaceAnimationRunner}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:SurfaceAnimationRunnerTest
+ * atest WmTests:SurfaceAnimationRunnerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index 0274b7d788ff..e71247173930 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -38,7 +38,7 @@ import org.mockito.MockitoAnnotations;
* Test class for {@link TaskSnapshotCache}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotCacheTest
+ * atest WmTests:TaskSnapshotCacheTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 8fe0cdbbd872..2e485dd1bec3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -53,7 +53,7 @@ import org.mockito.Mockito;
* Test class for {@link TaskSnapshotController}.
*
* Build/Install/Run:
- * * atest FrameworksServicesTests:TaskSnapshotControllerTest
+ * * atest WmTests:TaskSnapshotControllerTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index b5a5790a3a8c..eb8eb98fd484 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -47,7 +47,7 @@ import java.util.function.Predicate;
* Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
+ * atest WmTests:TaskSnapshotPersisterLoaderTest
*/
@MediumTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 2d418ffffcf6..ed87f3a0c604 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -53,7 +53,7 @@ import org.junit.runner.RunWith;
* Test class for {@link TaskSnapshotSurface}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:TaskSnapshotSurfaceTest
+ * atest WmTests:TaskSnapshotSurfaceTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
index 8936aadd5f92..3c0dd1e897f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -39,7 +39,7 @@ import java.util.function.Consumer;
* Tests for {@link WindowContainer#forAllWindows} and various implementations.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerTraversalTests
+ * atest WmTests:WindowContainerTraversalTests
*/
@SmallTest
@Presubmit
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 e081ca374808..7e248f854dcf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -92,7 +92,7 @@ import java.util.List;
* Tests for the {@link WindowState} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowStateTests
+ * atest WmTests:WindowStateTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ea8831571639..31a7f2437536 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,6 +44,7 @@ import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl.Transaction;
+import android.view.View;
import android.view.WindowManager;
import com.android.server.AttributeCache;
@@ -312,6 +313,16 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
}
+ static void makeWindowVisible(WindowState... windows) {
+ for (WindowState win : windows) {
+ win.mViewVisibility = View.VISIBLE;
+ win.mRelayoutCalled = true;
+ win.mHasSurface = true;
+ win.mHidden = false;
+ win.showLw(false /* doAnimation */, false /* requestAnim */);
+ }
+ }
+
/** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */
ActivityStack createTaskStackOnDisplay(DisplayContent dc) {
return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
new file mode 100644
index 000000000000..9cda08458640
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.utils;
+
+import static android.graphics.Bitmap.Config.ARGB_8888;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.view.Surface;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RotationAnimationUtilsTest {
+
+ private static final int BITMAP_HEIGHT = 100;
+ private static final int BITMAP_WIDTH = 100;
+ private static final int POINT_WIDTH = 1000;
+ private static final int POINT_HEIGHT = 2000;
+
+ private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+ private Matrix mMatrix;
+
+ @Before
+ public void setup() {
+ mMatrix = new Matrix();
+ }
+
+ @Test
+ public void blackLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void whiteImageBlackBorderLuma() {
+ Bitmap swBitmap = createBitmap(1);
+ setBorderLuma(swBitmap, 0);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(0, borderLuma, 0);
+ }
+
+ @Test
+ public void blackImageWhiteBorderLuma() {
+ Bitmap swBitmap = createBitmap(0);
+ setBorderLuma(swBitmap, 1);
+ GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+ float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+ assertEquals(1, borderLuma, 0);
+ }
+
+ @Test
+ public void rotate_0_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_0,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_WIDTH, newPoints.x, 0);
+ assertEquals(POINT_HEIGHT, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_90_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_90,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(POINT_WIDTH, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_180_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_180,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(0, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ @Test
+ public void rotate_270_bottomRight() {
+ RotationAnimationUtils.createRotationMatrix(Surface.ROTATION_270,
+ POINT_WIDTH, POINT_HEIGHT, mMatrix);
+ PointF newPoints = checkMappedPoints(POINT_WIDTH, POINT_HEIGHT);
+ assertEquals(POINT_HEIGHT, newPoints.x, 0);
+ assertEquals(0, newPoints.y, 0);
+ }
+
+ private PointF checkMappedPoints(int x, int y) {
+ final float[] fs = new float[] {x, y};
+ mMatrix.mapPoints(fs);
+ return new PointF(fs[0], fs[1]);
+ }
+
+ private Bitmap createBitmap(float luma) {
+ Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888);
+ for (int i = 0; i < BITMAP_WIDTH; i++) {
+ for (int j = 0; j < BITMAP_HEIGHT; j++) {
+ bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma));
+ }
+ }
+ return bitmap;
+ }
+
+ private GraphicBuffer swBitmapToGraphicsBuffer(Bitmap swBitmap) {
+ Bitmap hwBitmap = swBitmap.copy(Bitmap.Config.HARDWARE, false);
+ return hwBitmap.createGraphicBufferHandle();
+ }
+
+ private void setBorderLuma(Bitmap swBitmap, float luma) {
+ int i;
+ int width = swBitmap.getWidth();
+ int height = swBitmap.getHeight();
+ for (i = 0; i < width; i++) {
+ swBitmap.setPixel(i, 0, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(i, height - 1, Color.argb(1, luma, luma, luma));
+ }
+ for (i = 0; i < height; i++) {
+ swBitmap.setPixel(0, i, Color.argb(1, luma, luma, luma));
+ swBitmap.setPixel(width - 1, i, Color.argb(1, luma, luma, luma));
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index b75510b576f6..488ee78f6230 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -83,7 +83,7 @@ import com.android.server.wm.ActivityMetricsLaunchObserver;
* could transition to INTENT_STARTED.
*
* <p> If any bad transition happened, the state becomse UNKNOWN. The UNKNOWN state
- * could be * accumulated, because during the UNKNOWN state more IntentStarted may
+ * could be accumulated, because during the UNKNOWN state more IntentStarted may
* be triggered. To recover from UNKNOWN to INIT, all the accumualted IntentStarted
* should termniate.
*
@@ -100,7 +100,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
@Override
public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentStarted during UNKNOWN." + intent);
+ Log.wtf(TAG, "IntentStarted during UNKNOWN." + intent);
incAccIntentStartedEvents();
return;
}
@@ -110,32 +110,32 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
state != State.ACTIVITY_CANCELLED &&
state != State.ACTIVITY_FINISHED &&
state != State.REPORT_FULLY_DRAWN) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
incAccIntentStartedEvents();
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_STARTED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED));
state = State.INTENT_STARTED;
}
@Override
public void onIntentFailed() {
if (state == State.UNKNOWN) {
- Log.e(TAG, "IntentFailed during UNKNOWN.");
+ Log.wtf(TAG, "IntentFailed during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
incAccIntentStartedEvents();
return;
}
- Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_FAILED));
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED));
state = State.INTENT_FAILED;
}
@@ -143,11 +143,11 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
@Temperature int temperature) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunched during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunched during UNKNOWN.");
return;
}
if (state != State.INTENT_STARTED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
incAccIntentStartedEvents();
return;
@@ -160,12 +160,12 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
@Override
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchCancelled during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchCancelled during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
incAccIntentStartedEvents();
return;
@@ -179,13 +179,13 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onActivityLaunchFinished during UNKNOWN.");
+ Log.wtf(TAG, "onActivityLaunchFinished during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
if (state != State.ACTIVITY_LAUNCHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
incAccIntentStartedEvents();
return;
@@ -199,7 +199,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- Log.e(TAG, "onReportFullyDrawn during UNKNOWN.");
+ Log.wtf(TAG, "onReportFullyDrawn during UNKNOWN.");
return;
}
if (state == State.INIT) {
@@ -207,7 +207,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
}
if (state != State.ACTIVITY_FINISHED) {
- Log.e(TAG,
+ Log.wtf(TAG,
String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
return;
}
@@ -230,7 +230,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
private void incAccIntentStartedEvents() {
if (accIntentStartedEvents < 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if (accIntentStartedEvents == 0) {
state = State.UNKNOWN;
@@ -243,7 +243,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
private void decAccIntentStartedEvents() {
if (accIntentStartedEvents <= 0) {
throw new AssertionError(
- String.format("The number of unknows cannot be negative"));
+ String.format("The number of unknowns cannot be negative"));
}
if(accIntentStartedEvents == 1) {
state = State.INIT;
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 2abcc76fdccc..2abcc76fdccc 100644
--- a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 693603f36c68..4d5713259a0f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -29,7 +29,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
@@ -4205,8 +4204,11 @@ public class CarrierConfigManager {
/** @hide */
@Nullable
private ICarrierConfigLoader getICarrierConfigLoader() {
- return ICarrierConfigLoader.Stub
- .asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
+ return ICarrierConfigLoader.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getCarrierConfigServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index ce32dce834db..534546921ebf 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -191,6 +191,7 @@ public abstract class CellIdentity implements Parcelable {
*
* @hide
*/
+ @SystemApi
public abstract @NonNull CellIdentity sanitizeLocationInfo();
@Override
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 64776e377fa4..11931996009c 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -19,7 +19,6 @@ package android.telephony;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
@@ -38,7 +37,11 @@ public abstract class CellLocation {
*/
public static void requestLocationUpdate() {
try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
+ ITelephony phone = ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (phone != null) {
phone.updateServiceLocation();
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f31fafe36508..d28d750c6011 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -155,7 +155,17 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
* @param ss signal strength from modem.
*/
public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) {
- this(ss.csiRsrp, ss.csiRsrq, ss.csiSinr, ss.ssRsrp, ss.ssRsrq, ss.ssSinr);
+ this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq),
+ ss.ssSinr);
+ }
+
+ /**
+ * Flip sign cell strength value when taking in the value from hal
+ * @param val cell strength value
+ * @return flipped value
+ */
+ private static int flip(int val) {
+ return val != CellInfo.UNAVAILABLE ? -val : val;
}
/**
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 202da6817cb5..b10649c7208f 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -17,9 +17,7 @@
package android.telephony;
import android.annotation.IntDef;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import com.android.internal.telephony.ITelephony;
@@ -148,6 +146,9 @@ public class NetworkScan {
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5b12aed3e51b..66feb7bac25d 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2044,4 +2044,27 @@ public class ServiceState implements Parcelable {
public boolean isIwlanPreferred() {
return mIsIwlanPreferred;
}
+ /**
+ * @return {@code true}Returns True whenever the modem is searching for service.
+ * To check both CS and PS domain
+ */
+
+ public boolean isSearching() {
+ NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ if (psRegState != null && psRegState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) {
+ return true;
+ }
+
+ NetworkRegistrationInfo csRegState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ if (csRegState != null && csRegState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index fbe355e5c78b..db33be313941 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -35,7 +35,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -745,7 +744,11 @@ public final class SmsManager {
"Invalid pdu format. format must be either 3gpp or 3gpp2");
}
try {
- ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ ISms iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
if (iSms != null) {
iSms.injectSmsPduForSubscriber(
getSubscriptionId(), pdu, format, receivedIntent);
@@ -1535,7 +1538,10 @@ public final class SmsManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
@@ -1573,7 +1579,11 @@ public final class SmsManager {
}
private static ISms getISmsService() {
- return ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ return ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
}
/**
@@ -2007,7 +2017,11 @@ public final class SmsManager {
public boolean isSMSPromptEnabled() {
ISms iSms = null;
try {
- iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ iSms = ISms.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSmsServiceRegisterer()
+ .get());
return iSms.isSMSPromptEnabled();
} catch (RemoteException ex) {
return false;
@@ -2434,14 +2448,18 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed
* @throws IllegalArgumentException if contentUri is empty
+ * @deprecated use {@link MmsManager#sendMultimediaMessage} instead.
*/
public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
Bundle configOverrides, PendingIntent sentIntent) {
if (contentUri == null) {
throw new IllegalArgumentException("Uri contentUri null");
}
- MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri,
- locationUrl, configOverrides, sentIntent);
+ MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
+ if (m != null) {
+ m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides,
+ sentIntent);
+ }
}
/**
@@ -2465,6 +2483,7 @@ public final class SmsManager {
* @param downloadedIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is downloaded, or the download is failed
* @throws IllegalArgumentException if locationUrl or contentUri is empty
+ * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead.
*/
public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
Bundle configOverrides, PendingIntent downloadedIntent) {
@@ -2474,8 +2493,11 @@ public final class SmsManager {
if (contentUri == null) {
throw new IllegalArgumentException("Uri contentUri null");
}
- MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl,
- contentUri, configOverrides, downloadedIntent);
+ MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
+ if (m != null) {
+ m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri,
+ configOverrides, downloadedIntent);
+ }
}
// MMS send/download failure result codes
@@ -2517,9 +2539,9 @@ public final class SmsManager {
* </p>
*
* @return the bundle key/values pairs that contains MMS configuration values
+ * or an empty bundle if they cannot be found.
*/
- @Nullable
- public Bundle getCarrierConfigValues() {
+ @NonNull public Bundle getCarrierConfigValues() {
try {
ISms iSms = getISmsService();
if (iSms != null) {
@@ -2528,7 +2550,7 @@ public final class SmsManager {
} catch (RemoteException ex) {
// ignore it
}
- return null;
+ return new Bundle();
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 22eed6e026af..321753bc1776 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,6 @@ import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.provider.Telephony.SimInfo;
import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsMmTelManager;
@@ -265,7 +264,7 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID;
/**
* TelephonyProvider column name for a unique identifier for the subscription within the
@@ -274,18 +273,18 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String ICC_ID = "icc_id";
+ public static final String ICC_ID = SimInfo.ICC_ID;
/**
* TelephonyProvider column name for user SIM_SlOT_INDEX
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String SIM_SLOT_INDEX = "sim_id";
+ public static final String SIM_SLOT_INDEX = SimInfo.SIM_SLOT_INDEX;
/** SIM is not inserted */
/** @hide */
- public static final int SIM_NOT_INSERTED = -1;
+ public static final int SIM_NOT_INSERTED = SimInfo.SIM_NOT_INSERTED;
/**
* The slot-index for Bluetooth Remote-SIM subscriptions
@@ -300,23 +299,7 @@ public class SubscriptionManager {
* Default value is 0.
*/
/** @hide */
- public static final String SUBSCRIPTION_TYPE = "subscription_type";
-
- /**
- * TelephonyProvider column name white_listed_apn_data.
- * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
- * and mobile data is turned off by the user.
- * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
- * data connection to setup even if MMS is metered and mobile_data is turned off on that
- * subscription.
- *
- * Default value is 0.
- *
- * @deprecated Replaced by {@link #DATA_ENABLED_OVERRIDE_RULES}
- * @hide
- */
- @Deprecated
- public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+ public static final String SUBSCRIPTION_TYPE = SimInfo.SUBSCRIPTION_TYPE;
/**
* TelephonyProvider column name data_enabled_override_rules.
@@ -329,7 +312,15 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ public static final String DATA_ENABLED_OVERRIDE_RULES = SimInfo.DATA_ENABLED_OVERRIDE_RULES;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+ value = {
+ SUBSCRIPTION_TYPE_LOCAL_SIM,
+ SUBSCRIPTION_TYPE_REMOTE_SIM})
+ public @interface SubscriptionType {}
/**
* This constant is to designate a subscription as a Local-SIM Subscription.
@@ -337,7 +328,7 @@ public class SubscriptionManager {
* device.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM;
/**
* This constant is to designate a subscription as a Remote-SIM Subscription.
@@ -363,29 +354,21 @@ public class SubscriptionManager {
* was never seen before.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
- value = {
- SUBSCRIPTION_TYPE_LOCAL_SIM,
- SUBSCRIPTION_TYPE_REMOTE_SIM})
- public @interface SubscriptionType {}
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = SimInfo.SUBSCRIPTION_TYPE_REMOTE_SIM;
/**
* TelephonyProvider column name for user displayed name.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME = SimInfo.DISPLAY_NAME;
/**
* TelephonyProvider column name for the service provider name for the SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String CARRIER_NAME = "carrier_name";
+ public static final String CARRIER_NAME = SimInfo.CARRIER_NAME;
/**
* Default name resource
@@ -399,44 +382,44 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String NAME_SOURCE = "name_source";
+ public static final String NAME_SOURCE = SimInfo.NAME_SOURCE;
/**
* The name_source is the default, which is from the carrier id.
* @hide
*/
- public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+ public static final int NAME_SOURCE_DEFAULT = SimInfo.NAME_SOURCE_DEFAULT;
/**
* The name_source is from SIM EF_SPN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_SPN = 1;
+ public static final int NAME_SOURCE_SIM_SPN = SimInfo.NAME_SOURCE_SIM_SPN;
/**
* The name_source is from user input
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final int NAME_SOURCE_USER_INPUT = 2;
+ public static final int NAME_SOURCE_USER_INPUT = SimInfo.NAME_SOURCE_USER_INPUT;
/**
* The name_source is carrier (carrier app, carrier config, etc.)
* @hide
*/
- public static final int NAME_SOURCE_CARRIER = 3;
+ public static final int NAME_SOURCE_CARRIER = SimInfo.NAME_SOURCE_CARRIER;
/**
* The name_source is from SIM EF_PNN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_PNN = 4;
+ public static final int NAME_SOURCE_SIM_PNN = SimInfo.NAME_SOURCE_SIM_PNN;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"NAME_SOURCE_"},
value = {
- NAME_SOURCE_DEFAULT_SOURCE,
+ NAME_SOURCE_DEFAULT,
NAME_SOURCE_SIM_SPN,
NAME_SOURCE_USER_INPUT,
NAME_SOURCE_CARRIER,
@@ -449,67 +432,30 @@ public class SubscriptionManager {
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String COLOR = "color";
-
- /** @hide */
- public static final int COLOR_1 = 0;
-
- /** @hide */
- public static final int COLOR_2 = 1;
-
- /** @hide */
- public static final int COLOR_3 = 2;
-
- /** @hide */
- public static final int COLOR_4 = 3;
-
- /** @hide */
- public static final int COLOR_DEFAULT = COLOR_1;
+ public static final String COLOR = SimInfo.COLOR;
/**
* TelephonyProvider column name for the phone number of a SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String NUMBER = "number";
+ public static final String NUMBER = SimInfo.NUMBER;
/**
- * TelephonyProvider column name for the number display format of a SIM.
+ * TelephonyProvider column name for whether data roaming is enabled.
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
-
- /** @hide */
- public static final int DISPLAY_NUMBER_NONE = 0;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_FIRST = 1;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_LAST = 2;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
-
- /**
- * TelephonyProvider column name for permission for data roaming of a SIM.
- * <P>Type: INTEGER (int)</P>
- */
- /** @hide */
- public static final String DATA_ROAMING = "data_roaming";
+ public static final String DATA_ROAMING = SimInfo.DATA_ROAMING;
/** Indicates that data roaming is enabled for a subscription */
- public static final int DATA_ROAMING_ENABLE = 1;
+ public static final int DATA_ROAMING_ENABLE = SimInfo.DATA_ROAMING_ENABLE;
/** Indicates that data roaming is disabled for a subscription */
- public static final int DATA_ROAMING_DISABLE = 0;
-
- /** @hide */
- public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+ public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
/** @hide */
- public static final int SIM_PROVISIONED = 0;
+ public static final int DATA_ROAMING_DEFAULT = SimInfo.DATA_ROAMING_DEFAULT;
/**
* TelephonyProvider column name for subscription carrier id.
@@ -517,61 +463,61 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int) </p>
* @hide
*/
- public static final String CARRIER_ID = "carrier_id";
+ public static final String CARRIER_ID = SimInfo.CARRIER_ID;
/**
* @hide A comma-separated list of EHPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String EHPLMNS = "ehplmns";
+ public static final String EHPLMNS = SimInfo.EHPLMNS;
/**
* @hide A comma-separated list of HPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String HPLMNS = "hplmns";
+ public static final String HPLMNS = SimInfo.HPLMNS;
/**
* TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MCC_STRING = "mcc_string";
+ public static final String MCC_STRING = SimInfo.MCC_STRING;
/**
* TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MNC_STRING = "mnc_string";
+ public static final String MNC_STRING = SimInfo.MNC_STRING;
/**
* TelephonyProvider column name for the MCC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MCC = "mcc";
+ public static final String MCC = SimInfo.MCC;
/**
* TelephonyProvider column name for the MNC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MNC = "mnc";
+ public static final String MNC = SimInfo.MNC;
/**
* TelephonyProvider column name for the iso country code associated with a SIM.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ public static final String ISO_COUNTRY_CODE = SimInfo.ISO_COUNTRY_CODE;
/**
* TelephonyProvider column name for the sim provisioning status associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+ public static final String SIM_PROVISIONING_STATUS = SimInfo.SIM_PROVISIONING_STATUS;
/**
* TelephonyProvider column name for whether a subscription is embedded (that is, present on an
@@ -579,7 +525,7 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
* @hide
*/
- public static final String IS_EMBEDDED = "is_embedded";
+ public static final String IS_EMBEDDED = SimInfo.IS_EMBEDDED;
/**
* TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
@@ -587,7 +533,7 @@ public class SubscriptionManager {
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String CARD_ID = "card_id";
+ public static final String CARD_ID = SimInfo.CARD_ID;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -595,7 +541,7 @@ public class SubscriptionManager {
* <p>TYPE: BLOB
* @hide
*/
- public static final String ACCESS_RULES = "access_rules";
+ public static final String ACCESS_RULES = SimInfo.ACCESS_RULES;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -605,7 +551,7 @@ public class SubscriptionManager {
* @hide
*/
public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
- "access_rules_from_carrier_configs";
+ SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS;
/**
* TelephonyProvider column name identifying whether an embedded subscription is on a removable
@@ -615,79 +561,79 @@ public class SubscriptionManager {
* <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
* @hide
*/
- public static final String IS_REMOVABLE = "is_removable";
+ public static final String IS_REMOVABLE = SimInfo.IS_REMOVABLE;
/**
* TelephonyProvider column name for extreme threat in CB settings
* @hide
*/
- public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ public static final String CB_EXTREME_THREAT_ALERT = SimInfo.CB_EXTREME_THREAT_ALERT;
/**
* TelephonyProvider column name for severe threat in CB settings
*@hide
*/
- public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ public static final String CB_SEVERE_THREAT_ALERT = SimInfo.CB_SEVERE_THREAT_ALERT;
/**
* TelephonyProvider column name for amber alert in CB settings
*@hide
*/
- public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ public static final String CB_AMBER_ALERT = SimInfo.CB_AMBER_ALERT;
/**
* TelephonyProvider column name for emergency alert in CB settings
*@hide
*/
- public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ public static final String CB_EMERGENCY_ALERT = SimInfo.CB_EMERGENCY_ALERT;
/**
* TelephonyProvider column name for alert sound duration in CB settings
*@hide
*/
- public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ public static final String CB_ALERT_SOUND_DURATION = SimInfo.CB_ALERT_SOUND_DURATION;
/**
* TelephonyProvider column name for alert reminder interval in CB settings
*@hide
*/
- public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ public static final String CB_ALERT_REMINDER_INTERVAL = SimInfo.CB_ALERT_REMINDER_INTERVAL;
/**
* TelephonyProvider column name for enabling vibrate in CB settings
*@hide
*/
- public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ public static final String CB_ALERT_VIBRATE = SimInfo.CB_ALERT_VIBRATE;
/**
* TelephonyProvider column name for enabling alert speech in CB settings
*@hide
*/
- public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ public static final String CB_ALERT_SPEECH = SimInfo.CB_ALERT_SPEECH;
/**
* TelephonyProvider column name for ETWS test alert in CB settings
*@hide
*/
- public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ public static final String CB_ETWS_TEST_ALERT = SimInfo.CB_ETWS_TEST_ALERT;
/**
* TelephonyProvider column name for enable channel50 alert in CB settings
*@hide
*/
- public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ public static final String CB_CHANNEL_50_ALERT = SimInfo.CB_CHANNEL_50_ALERT;
/**
* TelephonyProvider column name for CMAS test alert in CB settings
*@hide
*/
- public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+ public static final String CB_CMAS_TEST_ALERT = SimInfo.CB_CMAS_TEST_ALERT;
/**
* TelephonyProvider column name for Opt out dialog in CB settings
*@hide
*/
- public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ public static final String CB_OPT_OUT_DIALOG = SimInfo.CB_OPT_OUT_DIALOG;
/**
* TelephonyProvider column name for enable Volte.
@@ -696,37 +642,37 @@ public class SubscriptionManager {
* {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
*@hide
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ public static final String ENHANCED_4G_MODE_ENABLED = SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* TelephonyProvider column name for enable VT (Video Telephony over IMS)
*@hide
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ public static final String VT_IMS_ENABLED = SimInfo.VT_IMS_ENABLED;
/**
* TelephonyProvider column name for enable Wifi calling
*@hide
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ public static final String WFC_IMS_ENABLED = SimInfo.WFC_IMS_ENABLED;
/**
* TelephonyProvider column name for Wifi calling mode
*@hide
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ public static final String WFC_IMS_MODE = SimInfo.WFC_IMS_MODE;
/**
* TelephonyProvider column name for Wifi calling mode in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ public static final String WFC_IMS_ROAMING_MODE = SimInfo.WFC_IMS_ROAMING_MODE;
/**
* TelephonyProvider column name for enable Wifi calling in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* TelephonyProvider column name for whether a subscription is opportunistic, that is,
@@ -735,7 +681,7 @@ public class SubscriptionManager {
* <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
* @hide
*/
- public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ public static final String IS_OPPORTUNISTIC = SimInfo.IS_OPPORTUNISTIC;
/**
* TelephonyProvider column name for group ID. Subscriptions with same group ID
@@ -744,7 +690,7 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String GROUP_UUID = "group_uuid";
+ public static final String GROUP_UUID = SimInfo.GROUP_UUID;
/**
* TelephonyProvider column name for group owner. It's the package name who created
@@ -752,14 +698,7 @@ public class SubscriptionManager {
*
* @hide
*/
- public static final String GROUP_OWNER = "group_owner";
-
- /**
- * TelephonyProvider column name for whether a subscription is metered or not, that is, whether
- * the network it connects to charges for subscription or not. For example, paid CBRS or unpaid.
- * @hide
- */
- public static final String IS_METERED = "is_metered";
+ public static final String GROUP_OWNER = SimInfo.GROUP_OWNER;
/**
* TelephonyProvider column name for the profile class of a subscription
@@ -767,7 +706,7 @@ public class SubscriptionManager {
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String PROFILE_CLASS = "profile_class";
+ public static final String PROFILE_CLASS = SimInfo.PROFILE_CLASS;
/**
* Profile class of the subscription
@@ -775,11 +714,11 @@ public class SubscriptionManager {
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "PROFILE_CLASS_" }, value = {
- PROFILE_CLASS_TESTING,
- PROFILE_CLASS_PROVISIONING,
- PROFILE_CLASS_OPERATIONAL,
- PROFILE_CLASS_UNSET,
- PROFILE_CLASS_DEFAULT
+ SimInfo.PROFILE_CLASS_TESTING,
+ SimInfo.PROFILE_CLASS_PROVISIONING,
+ SimInfo.PROFILE_CLASS_OPERATIONAL,
+ SimInfo.PROFILE_CLASS_UNSET,
+ SimInfo.PROFILE_CLASS_DEFAULT
})
public @interface ProfileClass {}
@@ -791,7 +730,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_TESTING = 0;
+ public static final int PROFILE_CLASS_TESTING = SimInfo.PROFILE_CLASS_TESTING;
/**
* A provisioning profile is pre-loaded onto the eUICC and
@@ -800,7 +739,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_PROVISIONING = 1;
+ public static final int PROFILE_CLASS_PROVISIONING = SimInfo.PROFILE_CLASS_PROVISIONING;
/**
* An operational profile can be pre-loaded or downloaded
@@ -809,7 +748,7 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_OPERATIONAL = 2;
+ public static final int PROFILE_CLASS_OPERATIONAL = SimInfo.PROFILE_CLASS_OPERATIONAL;
/**
* The profile class is unset. This occurs when profile class
@@ -818,14 +757,14 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_UNSET = -1;
+ public static final int PROFILE_CLASS_UNSET = SimInfo.PROFILE_CLASS_UNSET;
/**
* Default profile class
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+ public static final int PROFILE_CLASS_DEFAULT = SimInfo.PROFILE_CLASS_DEFAULT;
/**
* IMSI (International Mobile Subscriber Identity).
@@ -833,13 +772,13 @@ public class SubscriptionManager {
* @hide
*/
//TODO: add @SystemApi
- public static final String IMSI = "imsi";
+ public static final String IMSI = SimInfo.IMSI;
/**
* Whether uicc applications is set to be enabled or disabled. By default it's enabled.
* @hide
*/
- public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ public static final String UICC_APPLICATIONS_ENABLED = SimInfo.UICC_APPLICATIONS_ENABLED;
/**
* Broadcast Action: The user has changed one of the default subs related to
@@ -1023,8 +962,11 @@ public class SubscriptionManager {
private final INetworkPolicyManager getNetworkPolicy() {
if (mNetworkPolicy == null) {
- mNetworkPolicy = INetworkPolicyManager.Stub
- .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ mNetworkPolicy = INetworkPolicyManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getNetworkPolicyServiceRegisterer()
+ .get());
}
return mNetworkPolicy;
}
@@ -1041,6 +983,23 @@ public class SubscriptionManager {
*/
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
if (listener == null) return;
+ addOnSubscriptionsChangedListener(listener.mExecutor, listener);
+ }
+
+ /**
+ * Register for changes to the list of active {@link SubscriptionInfo} records or to the
+ * individual records themselves. When a change occurs the onSubscriptionsChanged method of
+ * the listener will be invoked immediately if there has been a notification. The
+ * onSubscriptionChanged method will also be triggered once initially when calling this
+ * function.
+ *
+ * @param listener an instance of {@link OnSubscriptionsChangedListener} with
+ * onSubscriptionsChanged overridden.
+ * @param executor the executor that will execute callbacks.
+ */
+ public void addOnSubscriptionsChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnSubscriptionsChangedListener listener) {
String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (DBG) {
logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
@@ -1052,7 +1011,7 @@ public class SubscriptionManager {
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistryManager != null) {
telephonyRegistryManager.addOnSubscriptionsChangedListener(listener,
- listener.mExecutor);
+ executor);
}
}
@@ -1185,7 +1144,11 @@ public class SubscriptionManager {
SubscriptionInfo subInfo = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1219,7 +1182,11 @@ public class SubscriptionManager {
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1253,7 +1220,11 @@ public class SubscriptionManager {
SubscriptionInfo result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
mContext.getOpPackageName(), mContext.getFeatureId());
@@ -1277,7 +1248,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1358,7 +1333,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> activeList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1409,7 +1388,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1448,7 +1431,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
}
@@ -1477,7 +1464,11 @@ public class SubscriptionManager {
public void requestEmbeddedSubscriptionInfoListRefresh() {
int cardId = TelephonyManager.from(mContext).getCardIdForDefaultEuicc();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1506,7 +1497,11 @@ public class SubscriptionManager {
@SystemApi
public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.requestEmbeddedSubscriptionInfoListRefresh(cardId);
}
@@ -1527,7 +1522,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1556,7 +1555,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -1577,7 +1580,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getActiveSubInfoCountMax();
}
@@ -1634,7 +1641,11 @@ public class SubscriptionManager {
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1668,7 +1679,11 @@ public class SubscriptionManager {
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) {
Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
return;
@@ -1771,7 +1786,11 @@ public class SubscriptionManager {
int result = INVALID_SIM_SLOT_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSlotIndex(subscriptionId);
}
@@ -1805,7 +1824,11 @@ public class SubscriptionManager {
int[] subId = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getSubId(slotIndex);
}
@@ -1829,7 +1852,11 @@ public class SubscriptionManager {
int result = INVALID_PHONE_INDEX;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getPhoneId(subId);
}
@@ -1863,7 +1890,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSubId();
}
@@ -1886,7 +1917,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultVoiceSubId();
}
@@ -1916,7 +1951,11 @@ public class SubscriptionManager {
public void setDefaultVoiceSubscriptionId(int subscriptionId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultVoiceSubId(subscriptionId);
}
@@ -1964,7 +2003,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultSmsSubId();
}
@@ -1990,7 +2033,11 @@ public class SubscriptionManager {
public void setDefaultSmsSubId(int subscriptionId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultSmsSubId(subscriptionId);
}
@@ -2028,7 +2075,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getDefaultDataSubId();
}
@@ -2054,7 +2105,11 @@ public class SubscriptionManager {
public void setDefaultDataSubId(int subscriptionId) {
if (VDBG) logd("setDataSubscription sub id = " + subscriptionId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setDefaultDataSubId(subscriptionId);
}
@@ -2085,7 +2140,11 @@ public class SubscriptionManager {
/** @hide */
public void clearSubscriptionInfo() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.clearSubInfo();
}
@@ -2221,7 +2280,11 @@ public class SubscriptionManager {
*/
public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
int[] subId = iSub.getActiveSubIdList(visibleOnly);
if (subId != null) return subId;
@@ -2272,7 +2335,11 @@ public class SubscriptionManager {
int simState = TelephonyManager.SIM_STATE_UNKNOWN;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
simState = iSub.getSimStateForSlotIndex(slotIndex);
}
@@ -2291,7 +2358,11 @@ public class SubscriptionManager {
*/
public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setSubscriptionProperty(subId, propKey, propValue);
}
@@ -2311,7 +2382,11 @@ public class SubscriptionManager {
Context context) {
String resultValue = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
resultValue = iSub.getSubscriptionProperty(subId, propKey,
context.getOpPackageName(), context.getFeatureId());
@@ -2453,7 +2528,11 @@ public class SubscriptionManager {
@UnsupportedAppUsage
public boolean isActiveSubId(int subId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -2756,7 +2835,11 @@ public class SubscriptionManager {
@TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) {
if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub == null) return;
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -2799,7 +2882,11 @@ public class SubscriptionManager {
public int getPreferredDataSubscriptionId() {
int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
preferredSubId = iSub.getPreferredDataSubscriptionId();
}
@@ -2830,7 +2917,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> subInfoList = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
}
@@ -2931,7 +3022,11 @@ public class SubscriptionManager {
ParcelUuid groupUuid = null;
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
} else {
@@ -2981,7 +3076,11 @@ public class SubscriptionManager {
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3033,7 +3132,11 @@ public class SubscriptionManager {
int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
} else {
@@ -3078,7 +3181,11 @@ public class SubscriptionManager {
List<SubscriptionInfo> result = null;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
} else {
@@ -3191,7 +3298,11 @@ public class SubscriptionManager {
logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.setSubscriptionEnabled(enable, subscriptionId);
}
@@ -3221,7 +3332,11 @@ public class SubscriptionManager {
logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled);
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
iSub.setUiccApplicationsEnabled(enabled, subscriptionId);
}
@@ -3251,7 +3366,11 @@ public class SubscriptionManager {
logd("canDisablePhysicalSubscription");
}
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.canDisablePhysicalSubscription();
}
@@ -3272,7 +3391,11 @@ public class SubscriptionManager {
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isSubscriptionEnabled(int subscriptionId) {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.isSubscriptionEnabled(subscriptionId);
}
@@ -3295,7 +3418,11 @@ public class SubscriptionManager {
int subId = INVALID_SUBSCRIPTION_ID;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
subId = iSub.getEnabledSubscriptionId(slotIndex);
}
@@ -3321,7 +3448,11 @@ public class SubscriptionManager {
int result = 0;
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
result = helper.callMethod(iSub);
}
@@ -3344,7 +3475,11 @@ public class SubscriptionManager {
*/
public static int getActiveDataSubscriptionId() {
try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ ISub iSub = ISub.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getSubscriptionServiceRegisterer()
+ .get());
if (iSub != null) {
return iSub.getActiveDataSubscriptionId();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index df8c26da7af9..607450b76917 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,7 +60,6 @@ import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
@@ -107,6 +106,7 @@ import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.SmsApplication;
+import com.android.telephony.Rlog;
import dalvik.system.VMRuntime;
@@ -785,30 +785,6 @@ public class TelephonyManager {
public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
/**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN type.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String containing the data APN.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY;
-
- /**
* Broadcast intent action for letting the default dialer to know to show voicemail
* notification.
*
@@ -5107,7 +5083,11 @@ public class TelephonyManager {
@UnsupportedAppUsage
private IPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
- return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
+ return IPhoneSubInfo.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPhoneSubServiceRegisterer()
+ .get());
}
/**
@@ -5320,11 +5300,19 @@ public class TelephonyManager {
}
private ITelephonyRegistry getTelephonyRegistry() {
- return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+ return ITelephonyRegistry.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRegistryServiceRegisterer()
+ .get());
}
private IOns getIOns() {
- return IOns.Stub.asInterface(ServiceManager.getService("ions"));
+ return IOns.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getOpportunisticNetworkServiceRegisterer()
+ .get());
}
//
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 96b6db75b370..8e6c170f255b 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -19,7 +19,6 @@ package android.telephony;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
-import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -29,7 +28,6 @@ import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.SparseArray;
import com.android.internal.telephony.ITelephony;
@@ -234,6 +232,9 @@ public final class TelephonyScanManager {
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 994c49cd2315..e16fffa69f8a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -21,8 +21,8 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.euicc.EuiccProfileInfo;
+import android.telephony.TelephonyFrameworkInitializer;
import android.util.Log;
import com.android.internal.telephony.euicc.IAuthenticateServerCallback;
@@ -148,7 +148,10 @@ public class EuiccCardManager {
private IEuiccCardController getIEuiccCardController() {
return IEuiccCardController.Stub.asInterface(
- ServiceManager.getService("euicc_card_controller"));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccCardControllerServiceRegisterer()
+ .get());
}
/**
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cb66a9650f2f..d5a48df149f1 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,7 +30,7 @@ import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccCardManager.ResetOption;
@@ -968,6 +968,10 @@ public class EuiccManager {
}
private static IEuiccController getIEuiccController() {
- return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
+ return IEuiccController.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getEuiccControllerService()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 057d22cd7eae..91514e9ebe28 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,14 +25,13 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
@@ -1018,7 +1017,10 @@ public class ImsMmTelManager implements RegistrationManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index d3fb37f005cd..4f0f089dfa79 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -26,8 +26,8 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.feature.ImsFeature;
@@ -362,7 +362,10 @@ public class ImsRcsManager implements RegistrationManager {
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index e4d63355625d..f0521802a167 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -25,14 +25,13 @@ import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
-import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsConfigCallback;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
@@ -415,7 +414,11 @@ public class ProvisioningManager {
}
private static boolean isImsAvailableOnDevice() {
- IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getPackageManagerServiceRegisterer()
+ .get());
if (pm == null) {
// For some reason package manger is not available.. This will fail internally anyways,
// so do not throw error and allow.
@@ -432,7 +435,10 @@ public class ProvisioningManager {
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
- ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
if (binder == null) {
throw new RuntimeException("Could not find Telephony Service.");
}
diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java
index ce03c3c799bb..1e93437a5a94 100644
--- a/telephony/java/android/telephony/ims/RcsControllerCall.java
+++ b/telephony/java/android/telephony/ims/RcsControllerCall.java
@@ -18,7 +18,7 @@ package android.telephony.ims;
import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IRcsMessage;
/**
@@ -35,8 +35,11 @@ class RcsControllerCall {
}
<R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException {
- IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(ServiceManager.getService(
- Context.TELEPHONY_RCS_MESSAGE_SERVICE));
+ IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyRcsMessageServiceRegisterer()
+ .get());
if (iRcsMessage == null) {
throw new RcsMessageStoreException("Could not connect to RCS storage service");
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 75e3f0a6393d..2e3f59a13670 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,12 +21,11 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.content.Context;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.util.Log;
@@ -365,7 +364,10 @@ public class RcsUceAdapter {
}
private IImsRcsController getIImsRcsController() {
- IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+ IBinder binder = TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get();
return IImsRcsController.Stub.asInterface(binder);
}
}
diff --git a/telephony/java/com/android/telephony/Rlog.java b/telephony/java/com/android/telephony/Rlog.java
new file mode 100644
index 000000000000..9d6c930de8f5
--- /dev/null
+++ b/telephony/java/com/android/telephony/Rlog.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.telephony;
+
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.internal.telephony.util.TelephonyUtils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * A copy of {@link android.telephony.Rlog} to be used within the telephony mainline module.
+ *
+ * @hide
+ */
+public final class Rlog {
+
+ private static final boolean USER_BUILD = TelephonyUtils.IS_USER;
+
+ private Rlog() {
+ }
+
+ private static int log(int priority, String tag, String msg) {
+ return Log.logToRadioBuffer(priority, tag, msg);
+ }
+
+ public static int v(String tag, String msg) {
+ return log(Log.VERBOSE, tag, msg);
+ }
+
+ public static int v(String tag, String msg, Throwable tr) {
+ return log(Log.VERBOSE, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int d(String tag, String msg) {
+ return log(Log.DEBUG, tag, msg);
+ }
+
+ public static int d(String tag, String msg, Throwable tr) {
+ return log(Log.DEBUG, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int i(String tag, String msg) {
+ return log(Log.INFO, tag, msg);
+ }
+
+ public static int i(String tag, String msg, Throwable tr) {
+ return log(Log.INFO, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, String msg) {
+ return log(Log.WARN, tag, msg);
+ }
+
+ public static int w(String tag, String msg, Throwable tr) {
+ return log(Log.WARN, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int w(String tag, Throwable tr) {
+ return log(Log.WARN, tag, Log.getStackTraceString(tr));
+ }
+
+ public static int e(String tag, String msg) {
+ return log(Log.ERROR, tag, msg);
+ }
+
+ public static int e(String tag, String msg, Throwable tr) {
+ return log(Log.ERROR, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
+ public static int println(int priority, String tag, String msg) {
+ return log(priority, tag, msg);
+ }
+
+ public static boolean isLoggable(String tag, int level) {
+ return Log.isLoggable(tag, level);
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param tag used to identify the source of a log message
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If tag is loggable in verbose mode or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(String tag, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Redact personally identifiable information for production users.
+ * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
+ * @param pii the personally identifiable information we want to apply secure hash on.
+ * @return If enablePiiLogging is set to true or pii is null, return the original input.
+ * otherwise return a secure Hash of input pii
+ */
+ public static String pii(boolean enablePiiLogging, Object pii) {
+ String val = String.valueOf(pii);
+ if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
+ return val;
+ }
+ return "[" + secureHash(val.getBytes()) + "]";
+ }
+
+ /**
+ * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+ *
+ * @return "****" if the build type is user, otherwise the hash
+ * @param input the bytes for which the secure hash should be computed.
+ */
+ private static String secureHash(byte[] input) {
+ // Refrain from logging user personal information in user build.
+ if (USER_BUILD) {
+ return "****";
+ }
+
+ MessageDigest messageDigest;
+
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ return "####";
+ }
+
+ byte[] result = messageDigest.digest(input);
+ return Base64.encodeToString(
+ result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+ }
+}
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 653282d0d365..1361df30e9d7 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -320,8 +320,9 @@ public class MemoryUsageTest extends InstrumentationTestCase {
UserHandle.USER_CURRENT);
}
- mAtm.startActivityAndWait(null, null, mLaunchIntent, mimeType,
- null, null, 0, mLaunchIntent.getFlags(), null, null,
+ mAtm.startActivityAndWait(null,
+ getInstrumentation().getContext().getBasePackageName(), mLaunchIntent,
+ mimeType, null, null, 0, mLaunchIntent.getFlags(), null, null,
UserHandle.USER_CURRENT_OR_SELF);
} catch (RemoteException e) {
Log.w(TAG, "Error launching app", e);
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 40169b8cdcd3..9e490f765eab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -324,6 +324,7 @@ public class StagedRollbackTest {
@Test
public void testNetworkPassedDoesNotRollback_Phase1() throws Exception {
+ // Remove available rollbacks and uninstall NetworkStack on /data/
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
@@ -332,6 +333,15 @@ public class StagedRollbackTest {
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
+
+ // Reduce health check deadline, here unlike the network failed case, we use
+ // a longer deadline because joining a network can take a much longer time for
+ // reasons external to the device than 'not joining'
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
+ Integer.toString(300000), false);
+ // Simulate re-installation of new NetworkStack with rollbacks enabled
+ installNetworkStackPackage();
}
@Test
@@ -343,6 +353,9 @@ public class StagedRollbackTest {
@Test
public void testNetworkPassedDoesNotRollback_Phase3() throws Exception {
+ // Sleep for > health check deadline. We expect no rollback should happen during sleeping.
+ // If the device reboots for rollback, this device test will fail as well as the host test.
+ Thread.sleep(TimeUnit.SECONDS.toMillis(310));
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
getNetworkStackPackageName())).isNull();
@@ -380,11 +393,6 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_cleanUp() throws Exception {
- RollbackUtils.getRollbackManager().expireRollbackForPackage(getModuleMetadataPackageName());
- }
-
- @Test
public void testRollbackDataPolicy_Phase1() throws Exception {
Uninstall.packages(TestApp.A, TestApp.B);
Install.multi(TestApp.A1, TestApp.B1).commit();
@@ -422,6 +430,16 @@ public class StagedRollbackTest {
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
}
+ @Test
+ public void testCleanUp() throws Exception {
+ // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
+ // committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
+ // so there is only one rollback to commit when testing native crashes.
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ }
+
private static void runShellCommand(String cmd) {
ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 4644d8aee306..91577c202df9 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -22,8 +22,8 @@ import static org.testng.Assert.assertThrows;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +53,11 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
getDevice().reboot();
}
+ @After
+ public void tearDown() throws Exception {
+ runPhase("testCleanUp");
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@@ -128,21 +133,8 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
* Tests passed network health check does not trigger watchdog staged rollbacks.
*/
@Test
- @Ignore("b/143514090")
public void testNetworkPassedDoesNotRollback() throws Exception {
- // Remove available rollbacks and uninstall NetworkStack on /data/
runPhase("testNetworkPassedDoesNotRollback_Phase1");
- // Reduce health check deadline, here unlike the network failed case, we use
- // a longer deadline because joining a network can take a much longer time for
- // reasons external to the device than 'not joining'
- getDevice().executeShellCommand("device_config put rollback "
- + "watchdog_request_timeout_millis 300000");
- // Simulate re-installation of new NetworkStack with rollbacks enabled
- getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
- + getNetworkStackPath());
-
- // Sleep to allow writes to disk before reboot
- Thread.sleep(5000);
// Reboot device to activate staged package
getDevice().reboot();
@@ -157,8 +149,6 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// on mobile data
getDevice().waitForDeviceAvailable();
- // Sleep for > health check deadline
- Thread.sleep(310000);
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
}
@@ -180,16 +170,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackWhitelistedApp() throws Exception {
- try {
- runPhase("testRollbackWhitelistedApp_Phase1");
- getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
- } finally {
- // testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
- // committed on a device which doesn't support checkpoint. Let's clean up the rollback
- // so there is only one rollback to commit when testing native crashes.
- runPhase("testRollbackWhitelistedApp_cleanUp");
- }
+ runPhase("testRollbackWhitelistedApp_Phase1");
+ getDevice().reboot();
+ runPhase("testRollbackWhitelistedApp_Phase2");
}
@Test
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index c16a0f446651..33d77d288e15 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -64,15 +64,15 @@ public class NetworkStatsTest {
@Test
public void testFindIndex() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12);
assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
@@ -94,21 +94,21 @@ public class NetworkStatsTest {
@Test
public void testFindIndexHinted() {
final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12);
// verify that we correctly find across regardless of hinting
@@ -143,27 +143,27 @@ public class NetworkStatsTest {
assertEquals(0, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
assertEquals(4, stats.size());
assertEquals(4, stats.internalSize());
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
+ stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
assertEquals(9, stats.size());
@@ -193,8 +193,8 @@ public class NetworkStatsTest {
public void testCombineExisting() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 10);
- stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
- stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
+ stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
+ stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
-128L, -1L, -1);
@@ -215,12 +215,12 @@ public class NetworkStatsTest {
@Test
public void testSubtractIdenticalData() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats result = after.subtract(before);
@@ -234,12 +234,12 @@ public class NetworkStatsTest {
@Test
public void testSubtractIdenticalRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
final NetworkStats result = after.subtract(before);
@@ -253,13 +253,13 @@ public class NetworkStatsTest {
@Test
public void testSubtractNewRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
final NetworkStats after = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
- .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
+ .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
final NetworkStats result = after.subtract(before);
@@ -275,11 +275,11 @@ public class NetworkStatsTest {
@Test
public void testSubtractMissingRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
+ .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
final NetworkStats after = new NetworkStats(TEST_START, 1)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
final NetworkStats result = after.subtract(before);
@@ -293,40 +293,40 @@ public class NetworkStatsTest {
@Test
public void testTotalBytes() throws Exception {
final NetworkStats iface = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
assertEquals(384L, iface.getTotalBytes());
final NetworkStats uidSet = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidSet.getTotalBytes());
final NetworkStats uidTag = new NetworkStats(TEST_START, 6)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
assertEquals(64L, uidTag.getTotalBytes());
final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidMetered.getTotalBytes());
final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
assertEquals(96L, uidRoaming.getTotalBytes());
}
@@ -343,11 +343,11 @@ public class NetworkStatsTest {
@Test
public void testGroupedByIfaceAll() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L)
- .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L);
final NetworkStats grouped = uidStats.groupedByIface();
@@ -361,19 +361,19 @@ public class NetworkStatsTest {
@Test
public void testGroupedByIface() throws Exception {
final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L);
final NetworkStats grouped = uidStats.groupedByIface();
@@ -390,19 +390,19 @@ public class NetworkStatsTest {
@Test
public void testAddAllValues() {
final NetworkStats first = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
final NetworkStats second = new NetworkStats(TEST_START, 2)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
first.combineAllValues(second);
@@ -421,19 +421,19 @@ public class NetworkStatsTest {
@Test
public void testGetTotal() {
final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
@@ -459,7 +459,7 @@ public class NetworkStatsTest {
assertEquals(0, after.size());
// Test 1 item stats.
- before.addValues(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
+ before.addEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
after = before.clone();
after.removeUids(new int[0]);
assertEquals(1, after.size());
@@ -469,12 +469,12 @@ public class NetworkStatsTest {
assertEquals(0, after.size());
// Append remaining test items.
- before.addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
+ before.addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
+ .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
assertEquals(7, before.size());
// Test remove with empty uid list.
@@ -505,12 +505,12 @@ public class NetworkStatsTest {
@Test
public void testClone() throws Exception {
final NetworkStats original = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
// make clone and mutate original
final NetworkStats clone = original.clone();
- original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
+ original.addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
assertEquals(3, original.size());
assertEquals(2, clone.size());
@@ -523,8 +523,8 @@ public class NetworkStatsTest {
public void testAddWhenEmpty() throws Exception {
final NetworkStats red = new NetworkStats(TEST_START, -1);
final NetworkStats blue = new NetworkStats(TEST_START, 5)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
+ .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
// We're mostly checking that we don't crash
red.combineAllValues(blue);
@@ -537,39 +537,39 @@ public class NetworkStatsTest {
final String underlyingIface = "wlan0";
final int testTag1 = 8888;
NetworkStats delta = new NetworkStats(TEST_START, 17)
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
- .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
- // VPN package also uses some traffic through unprotected network.
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
- .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- // Tag entries
- .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
- .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
- // Irrelevant entries
- .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
- // Underlying Iface entries
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
- .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
- 299L /* smaller than sum(tun0) */, 0L)
- .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface});
+ .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
+ .addEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ .addEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
+ .addEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
+ // VPN package also uses some traffic through unprotected network.
+ .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
+ .addEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ // Tag entries
+ .addEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
+ .addEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
+ // Irrelevant entries
+ .addEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
+ // Underlying Iface entries
+ .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
+ .addEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
+ .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
+ 299L /* smaller than sum(tun0) */, 0L)
+ .addEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
+
+ delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
assertEquals(20, delta.size());
// tunIface and TEST_IFACE entries are not changed.
@@ -634,21 +634,21 @@ public class NetworkStatsTest {
final String tunIface = "tun0";
final String underlyingIface = "wlan0";
NetworkStats delta = new NetworkStats(TEST_START, 9)
- // 2 different apps sent/receive data via tun0.
- .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
- .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
- // VPN package resends data through the tunnel (with exaggerated overhead)
- .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
- // 1 app already has some traffic on the underlying interface, the other doesn't yet
- .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
- // Traffic through the underlying interface via the vpn app.
- // This test should redistribute this data correctly.
- .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
+ // 2 different apps sent/receive data via tun0.
+ .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
+ .addEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
+ // VPN package resends data through the tunnel (with exaggerated overhead)
+ .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
+ // 1 app already has some traffic on the underlying interface, the other doesn't yet
+ .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
+ // Traffic through the underlying interface via the vpn app.
+ // This test should redistribute this data correctly.
+ .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
assertEquals(9, delta.size());
@@ -697,9 +697,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
assertEquals(3, stats.size());
@@ -724,9 +724,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
assertEquals(2, stats.size());
@@ -755,10 +755,10 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 4)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3)
- .addValues(entry4);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3)
+ .addEntry(entry4);
stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
assertEquals(3, stats.size());
@@ -778,8 +778,8 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2);
+ .addEntry(entry1)
+ .addEntry(entry2);
stats.filter(UID_ALL, new String[] { }, TAG_ALL);
assertEquals(0, stats.size());
@@ -802,9 +802,9 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3);
stats.filter(UID_ALL, INTERFACES_ALL, testTag);
assertEquals(2, stats.size());
@@ -831,10 +831,10 @@ public class NetworkStatsTest {
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
NetworkStats stats = new NetworkStats(TEST_START, 4)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3)
- .addValues(entry4);
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3)
+ .addEntry(entry4);
stats.filterDebugEntries();
@@ -891,14 +891,14 @@ public class NetworkStatsTest {
0 /* operations */);
final NetworkStats statsXt = new NetworkStats(TEST_START, 3)
- .addValues(appEntry)
- .addValues(xtRootUidEntry)
- .addValues(otherEntry);
+ .addEntry(appEntry)
+ .addEntry(xtRootUidEntry)
+ .addEntry(otherEntry);
final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3)
- .addValues(appEntry)
- .addValues(ebpfRootUidEntry)
- .addValues(otherEntry);
+ .addEntry(appEntry)
+ .addEntry(ebpfRootUidEntry)
+ .addEntry(otherEntry);
statsXt.apply464xlatAdjustments(stackedIface, false);
statsEbpf.apply464xlatAdjustments(stackedIface, true);
@@ -945,8 +945,8 @@ public class NetworkStatsTest {
0 /* operations */);
NetworkStats stats = new NetworkStats(TEST_START, 2)
- .addValues(firstEntry)
- .addValues(secondEntry);
+ .addEntry(firstEntry)
+ .addEntry(secondEntry);
// Empty map: no adjustment
stats.apply464xlatAdjustments(new ArrayMap<>(), false);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index c0f9dc14869f..f0e5774a5dea 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -326,14 +326,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -359,14 +359,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -391,14 +391,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
@@ -424,14 +424,14 @@ public class NetworkStatsObserversTest {
// Baseline
NetworkStats xtSnapshot = null;
NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
+ .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 4d42a612030d..6de068e48a38 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -298,11 +298,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
mService.setUidForeground(UID_RED, false);
mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
mService.setUidForeground(UID_RED, true);
@@ -407,9 +407,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 10);
forcePollAndWaitForIdle();
@@ -429,9 +429,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -443,10 +443,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
forcePollAndWaitForIdle();
@@ -480,10 +480,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
- .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
+ .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
forcePollAndWaitForIdle();
@@ -501,10 +501,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
- .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
+ .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_BLUE);
mServiceContext.sendBroadcast(intent);
@@ -536,8 +536,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 5);
forcePollAndWaitForIdle();
@@ -552,8 +552,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -564,10 +564,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
+ .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
+ .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
forcePollAndWaitForIdle();
@@ -591,9 +591,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
forcePollAndWaitForIdle();
@@ -608,9 +608,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
forcePollAndWaitForIdle();
// first verify entire history present
@@ -654,9 +654,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(entry1)
- .addValues(entry2)
- .addValues(entry3));
+ .addEntry(entry1)
+ .addEntry(entry2)
+ .addEntry(entry3));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
@@ -704,11 +704,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
.thenReturn(augmentedIfaceFilter);
when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
.thenReturn(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(uidStats));
+ .addEntry(uidStats));
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
.thenReturn(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(tetheredStats1)
- .addValues(tetheredStats2));
+ .addEntry(tetheredStats1)
+ .addEntry(tetheredStats2));
NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
@@ -745,8 +745,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
forcePollAndWaitForIdle();
@@ -760,10 +760,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
+ .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
mService.setUidForeground(UID_RED, true);
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
@@ -804,9 +804,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
// We layer them on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
@@ -843,9 +843,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
// on top by inspecting the iface properties.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
forcePollAndWaitForIdle();
@@ -885,10 +885,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// Traffic for UID_RED.
final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
+ .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
// All tethering traffic, both hardware and software.
final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+ .addEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
0L);
expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 7f0872c02613..7fa47f696b50 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -85,8 +85,9 @@ static int write_java_methods(
string indent("");
if (supportQ) {
// TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n");
- fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n");
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
+ fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+ fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
indent = " ";
}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 634f6746d815..09d5386dcfc5 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -106,8 +106,10 @@ java_defaults {
name: "framework-wifi-test-defaults",
sdk_version: "core_platform", // tests can use @CorePlatformApi's
libs: [
+ // order matters: classes in framework-wifi are resolved before framework, meaning
+ // @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
"framework-wifi",
- "framework-minus-apex",
+ "framework",
// if sdk_version="" this gets automatically included, but here we need to add manually.
"framework-res",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1678d5a4776b..71942f0f80f4 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -90,6 +90,8 @@ interface IWifiManager
void allowAutojoin(int netId, boolean choice);
+ void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+
boolean startScan(String packageName, String featureId);
List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a379c75360ac..f4c5b9168cd0 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -253,9 +253,12 @@ public class WifiConfiguration implements Parcelable {
/** LEAP/Network EAP (only used with LEAP) */
public static final int LEAP = 2;
+ /** SAE (Used only for WPA3-Personal) */
+ public static final int SAE = 3;
+
public static final String varName = "auth_alg";
- public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
+ public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
}
/**
@@ -468,10 +471,13 @@ public class WifiConfiguration implements Parcelable {
break;
case SECURITY_TYPE_SAE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
// Note: allowedSuiteBCiphers bitset will be set by the service once the
@@ -480,6 +486,8 @@ public class WifiConfiguration implements Parcelable {
break;
case SECURITY_TYPE_OWE:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
requirePMF = true;
break;
case SECURITY_TYPE_WAPI_PSK:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 378c67ba4fcb..e870481ccf26 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -545,15 +545,22 @@ public class WifiManager {
public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
/**
- * The look up key for an int that indicates why softAP started failed
- * currently support general and no_channel
- * @see #SAP_START_FAILURE_GENERAL
- * @see #SAP_START_FAILURE_NO_CHANNEL
- * @see #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION
+ * An extra containing the int error code for Soft AP start failure.
+ * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
+ * {@link android.content.Intent#getIntExtra}.
+ * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
+ * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
+ *
+ * The error code will be one of:
+ * {@link #SAP_START_FAILURE_GENERAL},
+ * {@link #SAP_START_FAILURE_NO_CHANNEL},
+ * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_FAILURE_REASON =
+ "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
/**
* The previous Wi-Fi state.
*
@@ -4103,6 +4110,23 @@ public class WifiManager {
}
/**
+ * Configure auto-join settings for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enableAutoJoin true to enable autojoin, false to disable autojoin.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinPasspoint(@NonNull String fqdn, boolean enableAutoJoin) {
+ try {
+ mService.allowAutojoinPasspoint(fqdn, enableAutoJoin);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 5befb54ce50a..1822e84fdd57 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,6 +17,7 @@
package android.net.wifi.hotspot2;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.net.wifi.hotspot2.pps.Policy;
@@ -423,6 +424,41 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * The auto-join configuration specifies whether or not the Passpoint Configuration is
+ * considered for auto-connection. If true then yes, if false then it isn't considered as part
+ * of auto-connection - but can still be manually connected to.
+ */
+ private boolean mIsAutoJoinEnabled = true;
+
+ /**
+ * Configures the auto-association status of this Passpoint configuration. A value of true
+ * indicates that the configuration will be considered for auto-connection, a value of false
+ * indicates that only manual connection will work - the framework will not auto-associate to
+ * this Passpoint network.
+ *
+ * @param autoJoinEnabled true to be considered for framework auto-connection, false otherwise.
+ * @hide
+ */
+ public void setAutoJoinEnabled(boolean autoJoinEnabled) {
+ mIsAutoJoinEnabled = autoJoinEnabled;
+ }
+
+ /**
+ * Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
+ * value of true indicates that auto-connection can happen, a value of false indicates that it
+ * cannot. However, even when auto-connection is not possible manual connection by the user is
+ * possible.
+ *
+ * @return the auto-join configuration: true for auto-connection (or join) enabled, false
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ public boolean isAutoJoinEnabled() {
+ return mIsAutoJoinEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -464,6 +500,7 @@ public final class PasspointConfiguration implements Parcelable {
mServiceFriendlyNames = source.mServiceFriendlyNames;
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
+ mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
}
@Override
@@ -493,6 +530,7 @@ public final class PasspointConfiguration implements Parcelable {
(HashMap<String, String>) mServiceFriendlyNames);
dest.writeBundle(bundle);
dest.writeInt(mCarrierId);
+ dest.writeBoolean(mIsAutoJoinEnabled);
}
@Override
@@ -523,6 +561,7 @@ public final class PasspointConfiguration implements Parcelable {
&& mUsageLimitDataLimit == that.mUsageLimitDataLimit
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
+ && mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -533,7 +572,7 @@ public final class PasspointConfiguration implements Parcelable {
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled);
}
@Override
@@ -587,6 +626,7 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
}
builder.append("CarrierId:" + mCarrierId);
+ builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
return builder.toString();
}
@@ -692,6 +732,7 @@ public final class PasspointConfiguration implements Parcelable {
"serviceFriendlyNames");
config.setServiceFriendlyNames(friendlyNamesMap);
config.mCarrierId = in.readInt();
+ config.mIsAutoJoinEnabled = in.readBoolean();
return config;
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index d58083c92df6..d91efbccc2de 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -182,6 +182,11 @@ public class BaseWifiService extends IWifiManager.Stub {
}
@Override
+ public void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 909cfefba941..8689a38c6b17 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -16,6 +16,10 @@
package android.net.wifi;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -328,4 +332,57 @@ public class WifiConfigurationTest {
assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i));
}
}
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for SAE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSae() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_SAE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for OWE security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForOwe() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_OWE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.requirePMF);
+ }
+
+ /**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for Suite-B security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForSuiteB() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.allowedGroupManagementCiphers
+ .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+ assertTrue(config.requirePMF);
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f9bd31d57ffc..5ac50a0d1c97 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1672,10 +1672,22 @@ public class WifiManagerTest {
@Test
public void testAllowAutojoin() throws Exception {
mWifiManager.allowAutojoin(1, true);
- verify(mWifiService).allowAutojoin(eq(1), eq(true));
+ verify(mWifiService).allowAutojoin(1, true);
}
/**
+ * Test behavior of {@link WifiManager#allowAutojoinPasspoint(String, boolean)}
+ * @throws Exception
+ */
+ @Test
+ public void testAllowAutojoinPasspoint() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.allowAutojoinPasspoint(fqdn, true);
+ verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
+ }
+
+
+ /**
* Test behavior of {@link WifiManager#disconnect()}
*/
@Test
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index f501b16d2c79..94054fdde8da 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -171,6 +171,7 @@ public class PasspointConfigurationTest {
assertFalse(config.validate());
assertFalse(config.validateForR2());
+ assertTrue(config.isAutoJoinEnabled());
}
/**