summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp19
-rw-r--r--apex/appsearch/apex_manifest.json2
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearch.java48
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java19
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl10
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java182
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResults.java83
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java183
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java9
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java118
-rw-r--r--apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl1
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java35
-rw-r--r--apex/extservices/apex_manifest.json2
-rw-r--r--apex/permission/apex_manifest.json2
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java8
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java8
-rw-r--r--apex/sdkextensions/manifest.json2
-rw-r--r--apex/statsd/apex_manifest.json2
-rw-r--r--apex/statsd/framework/Android.bp11
-rw-r--r--apex/statsd/framework/java/android/app/StatsManager.java (renamed from core/java/android/app/StatsManager.java)7
-rw-r--r--apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java77
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java6
-rw-r--r--api/current.txt680
-rwxr-xr-xapi/system-current.txt398
-rw-r--r--api/system-lint-baseline.txt9
-rw-r--r--api/test-current.txt190
-rw-r--r--api/test-lint-baseline.txt28
-rw-r--r--cmds/statsd/src/atoms.proto1
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/app/AppGlobals.java16
-rw-r--r--core/java/android/app/AppOpsManager.java1
-rw-r--r--core/java/android/app/ContextImpl.java78
-rw-r--r--core/java/android/app/SystemServiceRegistry.java30
-rw-r--r--core/java/android/app/WindowContext.java123
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java127
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl7
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java4
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl3
-rw-r--r--core/java/android/content/Context.java92
-rw-r--r--core/java/android/content/ContextWrapper.java11
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl6
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/InstallationFile.java3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java86
-rw-r--r--core/java/android/content/pm/PackageManager.java52
-rw-r--r--core/java/android/content/pm/ProcessInfo.java88
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackage.java4
-rw-r--r--core/java/android/content/pm/parsing/ApkParseUtils.java15
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java250
-rw-r--r--core/java/android/content/pm/parsing/PackageImpl.java30
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoUtils.java21
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java3
-rw-r--r--core/java/android/hardware/CameraStatus.java3
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java152
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java20
-rw-r--r--core/java/android/hardware/lights/ILightsManager.aidl33
-rw-r--r--core/java/android/hardware/lights/Light.aidl20
-rw-r--r--core/java/android/hardware/lights/Light.java105
-rw-r--r--core/java/android/hardware/lights/LightState.aidl20
-rw-r--r--core/java/android/hardware/lights/LightState.java84
-rw-r--r--core/java/android/hardware/lights/LightsManager.java204
-rw-r--r--core/java/android/hardware/lights/LightsRequest.java95
-rw-r--r--core/java/android/hardware/location/ContextHubInfo.java25
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java2
-rw-r--r--core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java42
-rw-r--r--core/java/android/hardware/soundtrigger/KeyphraseMetadata.aidl19
-rw-r--r--core/java/android/hardware/soundtrigger/KeyphraseMetadata.java158
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java235
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java18
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.aidl21
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.java281
-rw-r--r--core/java/android/net/ConnectivityManager.java240
-rw-r--r--core/java/android/net/LinkAddress.java174
-rw-r--r--core/java/android/net/NetworkAgent.java5
-rw-r--r--core/java/android/net/NetworkKey.java9
-rw-r--r--core/java/android/net/NetworkScoreManager.java39
-rw-r--r--core/java/android/net/StringNetworkSpecifier.java2
-rw-r--r--core/java/android/os/BatteryStatsManager.java28
-rw-r--r--core/java/android/os/StatsServiceManager.java124
-rw-r--r--core/java/android/os/TelephonyServiceManager.java27
-rw-r--r--core/java/android/os/connectivity/WifiBatteryStats.java241
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/Settings.java57
-rw-r--r--core/java/android/provider/Telephony.java194
-rw-r--r--core/java/android/security/ConfirmationPrompt.java24
-rw-r--r--core/java/android/service/autofill/FillResponse.java42
-rw-r--r--core/java/android/service/autofill/InlinePresentation.java57
-rw-r--r--core/java/android/service/dataloader/DataLoaderService.java11
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java95
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java21
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java2
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java76
-rw-r--r--core/java/android/util/FeatureFlagUtils.java6
-rw-r--r--core/java/android/util/SparseSetArray.java4
-rw-r--r--core/java/android/view/Display.java10
-rw-r--r--core/java/android/view/IWindowManager.aidl23
-rw-r--r--core/java/android/view/ImeFocusController.java45
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java11
-rw-r--r--core/java/android/view/InsetsController.java26
-rw-r--r--core/java/android/view/Surface.java31
-rw-r--r--core/java/android/view/SurfaceControl.java30
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java130
-rw-r--r--core/java/android/view/SurfaceView.java44
-rw-r--r--core/java/android/view/View.java165
-rw-r--r--core/java/android/view/ViewGroup.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java19
-rw-r--r--core/java/android/view/Window.java98
-rw-r--r--core/java/android/view/WindowInsets.java103
-rw-r--r--core/java/android/view/WindowInsetsAnimationCallback.java95
-rw-r--r--core/java/android/view/WindowInsetsController.java45
-rw-r--r--core/java/android/view/WindowManager.java224
-rw-r--r--core/java/android/view/WindowManagerImpl.java79
-rw-r--r--core/java/android/view/WindowMetrics.java58
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java333
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionInfo.java77
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java18
-rw-r--r--core/java/android/widget/Editor.java75
-rw-r--r--core/java/android/widget/ProgressBar.java7
-rw-r--r--core/java/android/widget/TextView.java1
-rw-r--r--core/java/android/widget/Toast.java2
-rw-r--r--core/java/android/widget/WidgetFlags.java60
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java42
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java65
-rw-r--r--core/java/com/android/internal/app/ChooserListAdapter.java5
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java15
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl17
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java156
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java7
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java3
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java15
-rw-r--r--core/java/com/android/internal/app/ResolverViewPager.java (renamed from core/java/com/android/internal/app/WrapHeightViewPager.java)29
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java29
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java2
-rw-r--r--core/java/com/android/internal/policy/DecorView.java27
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java56
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java51
-rw-r--r--core/jni/android_media_AudioEffectDescriptor.cpp26
-rw-r--r--core/jni/android_media_AudioSystem.cpp96
-rw-r--r--core/jni/android_view_Surface.cpp7
-rw-r--r--core/jni/android_view_SurfaceControl.cpp10
-rw-r--r--core/proto/android/hardware/location/context_hub_info.proto49
-rw-r--r--core/proto/android/os/incident.proto6
-rw-r--r--core/proto/android/server/location/context_hub.proto60
-rw-r--r--core/res/AndroidManifest.xml42
-rw-r--r--core/res/res/layout/autofill_inline_suggestion.xml36
-rw-r--r--core/res/res/layout/chooser_grid.xml29
-rw-r--r--core/res/res/layout/resolver_list.xml42
-rw-r--r--core/res/res/layout/resolver_list_per_profile.xml4
-rw-r--r--core/res/res/layout/resolver_list_with_default.xml44
-rw-r--r--core/res/res/values/attrs.xml8
-rw-r--r--core/res/res/values/attrs_manifest.xml49
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/config.xml82
-rw-r--r--core/res/res/values/public.xml6
-rw-r--r--core/res/res/values/strings.xml10
-rw-r--r--core/res/res/values/styles.xml16
-rw-r--r--core/res/res/values/symbols.xml19
-rw-r--r--core/res/res/values/themes.xml7
-rw-r--r--core/tests/coretests/src/android/app/appsearch/SnippetTest.java200
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java3
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java8
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java2
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java26
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java229
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java157
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java35
-rw-r--r--core/tests/coretests/src/com/android/internal/app/MatcherUtils.java51
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java246
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java38
-rw-r--r--core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java10
-rw-r--r--data/etc/com.android.documentsui.xml1
-rw-r--r--data/etc/platform.xml4
-rw-r--r--drm/java/android/drm/DrmConvertedStatus.java2
-rw-r--r--drm/java/android/drm/DrmErrorEvent.java2
-rw-r--r--drm/java/android/drm/DrmEvent.java2
-rw-r--r--drm/java/android/drm/DrmInfo.java2
-rw-r--r--drm/java/android/drm/DrmInfoEvent.java2
-rw-r--r--drm/java/android/drm/DrmInfoRequest.java2
-rw-r--r--drm/java/android/drm/DrmInfoStatus.java2
-rw-r--r--drm/java/android/drm/DrmManagerClient.java2
-rw-r--r--drm/java/android/drm/DrmOutputStream.java2
-rw-r--r--drm/java/android/drm/DrmRights.java2
-rw-r--r--drm/java/android/drm/DrmStore.java2
-rw-r--r--drm/java/android/drm/DrmSupportInfo.java2
-rw-r--r--drm/java/android/drm/DrmUtils.java2
-rw-r--r--drm/java/android/drm/ProcessedData.java2
-rw-r--r--libs/hwui/DisplayListOps.in48
-rw-r--r--libs/hwui/RecordingCanvas.cpp24
-rw-r--r--libs/hwui/RecordingCanvas.h4
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp9
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp5
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp4
-rw-r--r--libs/input/PointerController.h2
-rw-r--r--location/java/android/location/GnssClock.java217
-rw-r--r--location/java/android/location/GnssMeasurement.java320
-rw-r--r--location/java/android/location/GnssStatus.java1
-rw-r--r--location/java/com/android/internal/location/ProviderRequest.java1
-rw-r--r--media/java/android/media/AudioDeviceInfo.java34
-rw-r--r--media/java/android/media/AudioManager.java64
-rw-r--r--media/java/android/media/AudioPlaybackCaptureConfiguration.java48
-rw-r--r--media/java/android/media/AudioSystem.java7
-rw-r--r--media/java/android/media/AudioTrack.java32
-rw-r--r--media/java/android/media/IAudioService.aidl4
-rw-r--r--media/java/android/media/audiofx/AudioEffect.java8
-rw-r--r--media/java/android/media/audiopolicy/AudioMixingRule.java77
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java75
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicyConfig.java8
-rw-r--r--media/java/android/media/session/MediaSession.java4
-rw-r--r--media/java/android/media/tv/TvContentRating.java7
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java14
-rw-r--r--media/java/android/media/tv/tuner/filter/MediaEvent.java13
-rw-r--r--media/java/android/media/voice/KeyphraseModelManager.java144
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java6
-rw-r--r--native/android/libandroid.map.txt1
-rw-r--r--native/android/surface_control.cpp15
-rw-r--r--native/graphics/jni/imagedecoder.cpp14
-rw-r--r--native/graphics/jni/libjnigraphics.map.txt1
-rw-r--r--opengl/java/com/google/android/gles_jni/EGLImpl.java3
-rw-r--r--opengl/java/com/google/android/gles_jni/GLImpl.java3
-rw-r--r--packages/CarSystemUI/res/layout/super_notification_shade.xml18
-rw-r--r--packages/CarSystemUI/res/layout/super_status_bar.xml19
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java85
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextController.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java100
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java11
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp4
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl5
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl5
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl32
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java66
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java493
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl30
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java12
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java45
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java9
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java10
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java31
-rw-r--r--proto/src/system_messages.proto4
-rw-r--r--services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java17
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java125
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java7
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java9
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java26
-rw-r--r--services/core/java/com/android/server/BatteryService.java6
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java171
-rw-r--r--services/core/java/com/android/server/RescueParty.java169
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java506
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java162
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java35
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java9
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java135
-rw-r--r--services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java8
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java4
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java22
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java4
-rw-r--r--services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java8
-rw-r--r--services/core/java/com/android/server/lights/LightsManager.java5
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java320
-rw-r--r--services/core/java/com/android/server/lights/LogicalLight.java (renamed from services/core/java/com/android/server/lights/Light.java)40
-rw-r--r--services/core/java/com/android/server/lights/OWNERS3
-rw-r--r--services/core/java/com/android/server/location/ActivityRecognitionProxy.java118
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientBroker.java23
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientManager.java50
-rw-r--r--services/core/java/com/android/server/location/ContextHubService.java22
-rw-r--r--services/core/java/com/android/server/location/GeocoderProxy.java40
-rw-r--r--services/core/java/com/android/server/location/GeofenceProxy.java88
-rw-r--r--services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java99
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java92
-rw-r--r--services/core/java/com/android/server/location/LocationRequestStatistics.java14
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java50
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java10
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java49
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java42
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java4
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java49
-rw-r--r--services/core/java/com/android/server/policy/GlobalKeyManager.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java2
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java10
-rw-r--r--services/core/java/com/android/server/utils/FlagNamespaceUtils.java151
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java173
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp32
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp43
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd1
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java294
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java201
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java10
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java129
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java173
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java4
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java22
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java210
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java40
-rw-r--r--telecomm/java/android/telecom/CallerInfoAsyncQuery.java3
-rw-r--r--telephony/OWNERS12
-rw-r--r--telephony/common/com/android/internal/telephony/SmsApplication.java10
-rw-r--r--telephony/common/com/google/android/mms/ContentType.java2
-rw-r--r--telephony/common/com/google/android/mms/InvalidHeaderValueException.java2
-rw-r--r--telephony/common/com/google/android/mms/MmsException.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/Base64.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/CharacterSets.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/DeliveryInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/EncodedStringValue.java3
-rw-r--r--telephony/common/com/google/android/mms/pdu/GenericPdu.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/NotificationInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/NotifyRespInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduBody.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduComposer.java3
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduContentTypes.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduHeaders.java2
-rwxr-xr-xtelephony/common/com/google/android/mms/pdu/PduParser.java3
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduPart.java3
-rwxr-xr-xtelephony/common/com/google/android/mms/pdu/PduPersister.java3
-rw-r--r--telephony/common/com/google/android/mms/pdu/QuotedPrintable.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/ReadOrigInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/ReadRecInd.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/RetrieveConf.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/SendConf.java2
-rw-r--r--telephony/common/com/google/android/mms/pdu/SendReq.java3
-rw-r--r--telephony/common/com/google/android/mms/util/AbstractCache.java3
-rw-r--r--telephony/common/com/google/android/mms/util/DownloadDrmHelper.java3
-rw-r--r--telephony/common/com/google/android/mms/util/DrmConvertSession.java3
-rw-r--r--telephony/common/com/google/android/mms/util/PduCache.java3
-rw-r--r--telephony/common/com/google/android/mms/util/PduCacheEntry.java2
-rw-r--r--telephony/common/com/google/android/mms/util/SqliteWrapper.java3
-rw-r--r--telephony/java/android/service/euicc/EuiccService.java61
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java55
-rw-r--r--telephony/java/android/telephony/CellIdentityLte.java13
-rw-r--r--telephony/java/android/telephony/CellIdentityNr.java42
-rw-r--r--telephony/java/android/telephony/ModemActivityInfo.java16
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java13
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java90
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java448
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java8
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java11
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java17
-rw-r--r--telephony/java/com/android/ims/ImsUtInterface.java6
-rw-r--r--telephony/java/com/android/ims/internal/IImsUt.aidl6
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl9
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java31
-rw-r--r--telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl4
-rw-r--r--test-mock/api/test-current.txt1
-rw-r--r--test-mock/src/android/test/mock/MockContext.java7
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp18
-rw-r--r--tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java28
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java14
-rw-r--r--tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java13
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java24
-rw-r--r--tests/net/common/java/android/net/LinkAddressTest.java83
-rw-r--r--tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java196
-rw-r--r--wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl3
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl15
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java14
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java89
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java45
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pConfig.java10
-rw-r--r--wifi/java/com/android/server/wifi/BaseWifiService.java13
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java39
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java3
419 files changed, 14860 insertions, 3785 deletions
diff --git a/Android.bp b/Android.bp
index 58f6119c2243..9411eeca834c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -297,6 +297,8 @@ filegroup {
],
}
+// AIDL files under these paths are mixture of public and private ones.
+// They shouldn't be exported across module boundaries.
java_defaults {
name: "framework-aidl-export-defaults",
aidl: {
@@ -321,12 +323,6 @@ java_defaults {
"wifi/aidl-export",
],
},
-
- required: [
- // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
- "gps_debug.conf",
- "protolog.conf.json.gz",
- ],
}
// Collection of classes that are generated from non-Java files that are not listed in
@@ -344,6 +340,7 @@ java_library {
"android.hardware.cas-V1.2-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.gnss-V1.0-java",
+ "android.hardware.gnss-V2.1-java",
"android.hardware.health-V1.0-java-constants",
"android.hardware.radio-V1.0-java",
"android.hardware.radio-V1.1-java",
@@ -416,6 +413,12 @@ java_defaults {
"view-inspector-annotation-processor",
"staledataclass-annotation-processor",
],
+
+ required: [
+ // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
+ "gps_debug.conf",
+ "protolog.conf.json.gz",
+ ],
}
filegroup {
@@ -539,7 +542,6 @@ java_library {
java_library {
name: "framework-annotation-proc",
- defaults: ["framework-aidl-export-defaults"],
srcs: [":framework-all-sources"],
libs: [
"app-compat-annotations",
@@ -713,7 +715,10 @@ filegroup {
name: "framework-tethering-annotations",
srcs: [
"core/java/android/annotation/NonNull.java",
+ "core/java/android/annotation/Nullable.java",
+ "core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/annotation/TestApi.java",
],
}
// Build ext.jar
diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json
index 273b867e8f98..39a2d38fa642 100644
--- a/apex/appsearch/apex_manifest.json
+++ b/apex/appsearch/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.appsearch",
- "version": 1
+ "version": 300000000
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java
index fd201866e702..8bf13eec6249 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java
@@ -101,6 +101,54 @@ public final class AppSearch {
this(document.mProto, document.mPropertyBundle);
}
+ /** @hide */
+ Document(@NonNull DocumentProto documentProto) {
+ this(documentProto, new Bundle());
+ for (int i = 0; i < documentProto.getPropertiesCount(); i++) {
+ PropertyProto property = documentProto.getProperties(i);
+ String name = property.getName();
+ if (property.getStringValuesCount() > 0) {
+ String[] values = new String[property.getStringValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getStringValues(j);
+ }
+ mPropertyBundle.putStringArray(name, values);
+ } else if (property.getInt64ValuesCount() > 0) {
+ long[] values = new long[property.getInt64ValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getInt64Values(j);
+ }
+ mPropertyBundle.putLongArray(property.getName(), values);
+ } else if (property.getDoubleValuesCount() > 0) {
+ double[] values = new double[property.getDoubleValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getDoubleValues(j);
+ }
+ mPropertyBundle.putDoubleArray(property.getName(), values);
+ } else if (property.getBooleanValuesCount() > 0) {
+ boolean[] values = new boolean[property.getBooleanValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getBooleanValues(j);
+ }
+ mPropertyBundle.putBooleanArray(property.getName(), values);
+ } else if (property.getBytesValuesCount() > 0) {
+ byte[][] values = new byte[property.getBytesValuesCount()][];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = property.getBytesValues(j).toByteArray();
+ }
+ mPropertyBundle.putObject(name, values);
+ } else if (property.getDocumentValuesCount() > 0) {
+ Document[] values = new Document[property.getDocumentValuesCount()];
+ for (int j = 0; j < values.length; j++) {
+ values[j] = new Document(property.getDocumentValues(j));
+ }
+ mPropertyBundle.putObject(name, values);
+ } else {
+ throw new IllegalStateException("Unknown type of value: " + name);
+ }
+ }
+ }
+
/**
* Creates a new {@link Document.Builder}.
*
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index e3f6b3de433a..15c336820df7 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -26,6 +26,7 @@ import com.android.internal.infra.AndroidFuture;
import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.StatusProto;
import com.google.android.icing.protobuf.InvalidProtocolBufferException;
@@ -186,28 +187,28 @@ public class AppSearchManager {
*<p>Currently we support following features in the raw query format:
* <ul>
* <li>AND
- * AND joins (e.g. “match documents that have both the terms ‘dog’ and
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
* ‘cat’”).
* Example: hello world matches documents that have both ‘hello’ and ‘world’
* <li>OR
- * OR joins (e.g. “match documents that have either the term ‘dog’ or
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
* ‘cat’”).
* Example: dog OR puppy
* <li>Exclusion
- * Exclude a term (e.g. “match documents that do
+ * <p>Exclude a term (e.g. “match documents that do
* not have the term ‘dog’”).
* Example: -dog excludes the term ‘dog’
* <li>Grouping terms
- * Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
* “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
* Example: (dog puppy) (cat kitten) two one group containing two terms.
* <li>Property restricts
- * which properties of a document to specifically match terms in (e.g.
+ * <p> Specifies which properties of a document to specifically match terms in (e.g.
* “match documents where the ‘subject’ property contains ‘important’”).
* Example: subject:important matches documents with the term ‘important’ in the
* ‘subject’ property
* <li>Schema type restricts
- * This is similar to property restricts, but allows for restricts on top-level document
+ * <p>This is similar to property restricts, but allows for restricts on top-level document
* fields, such as schema_type. Clients should be able to limit their query to documents of
* a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
* Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
@@ -263,7 +264,11 @@ public class AppSearchManager {
}, executor);
try {
- mService.query(queryExpression, searchSpec.getProto().toByteArray(), future);
+ SearchSpecProto searchSpecProto = searchSpec.getSearchSpecProto();
+ searchSpecProto = searchSpecProto.toBuilder().setQuery(queryExpression).build();
+ mService.query(searchSpecProto.toByteArray(),
+ searchSpec.getResultSpecProto().toByteArray(),
+ searchSpec.getScoringSpecProto().toByteArray(), future);
} catch (RemoteException e) {
future.completeExceptionally(e);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 20c8af985c21..eef41ed7104d 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -47,12 +47,14 @@ interface IAppSearchManager {
void putDocuments(in List documentsBytes, in AndroidFuture<AppSearchBatchResult> callback);
/**
- * Searches a document based on a given query string.
+ * Searches a document based on a given specifications.
*
- * @param queryExpression Query String to search.
- * @param searchSpec Serialized SearchSpecProto.
+ * @param searchSpecBytes Serialized SearchSpecProto.
+ * @param resultSpecBytes Serialized SearchResultsProto.
+ * @param scoringSpecBytes Serialized ScoringSpecProto.
* @param callback {@link AndroidFuture}. Will be completed with a serialized
* {@link SearchResultsProto}, or completed exceptionally if query fails.
*/
- void query(in String queryExpression, in byte[] searchSpecBytes, in AndroidFuture callback);
+ void query(in byte[] searchSpecBytes, in byte[] resultSpecBytes,
+ in byte[] scoringSpecBytes, in AndroidFuture callback);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
new file mode 100644
index 000000000000..6aa91a3fe9e4
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import android.annotation.NonNull;
+import android.util.Range;
+
+import com.google.android.icing.proto.SnippetMatchProto;
+
+/**
+ * Snippet: It refers to a substring of text from the content of document that is returned as a
+ * part of search result.
+ * This class represents a match objects for any Snippets that might be present in
+ * {@link SearchResults} from query. Using this class user can get the full text, exact matches and
+ * Snippets of document content for a given match.
+ *
+ * <p>Class Example 1:
+ * A document contains following text in property subject:
+ * <p>A commonly used fake word is foo. Another nonsense word that’s used a lot is bar.
+ *
+ * <p>If the queryExpression is "foo".
+ *
+ * <p>{@link MatchInfo#getPropertyPath()} returns "subject"
+ * <p>{@link MatchInfo#getFullText()} returns "A commonly used fake word is foo. Another nonsense
+ * word that’s used a lot is bar."
+ * <p>{@link MatchInfo#getExactMatchPosition()} returns [29, 32]
+ * <p>{@link MatchInfo#getExactMatch()} returns "foo"
+ * <p>{@link MatchInfo#getSnippetPosition()} returns [29, 41]
+ * <p>{@link MatchInfo#getSnippet()} returns "is foo. Another"
+ * <p>
+ * <p>Class Example 2:
+ * A document contains a property name sender which contains 2 property names name and email, so
+ * we will have 2 property paths: {@code sender.name} and {@code sender.email}.
+ * <p> Let {@code sender.name = "Test Name Jr."} and {@code sender.email = "TestNameJr@gmail.com"}
+ *
+ * <p>If the queryExpression is "Test". We will have 2 matches.
+ *
+ * <p> Match-1
+ * <p>{@link MatchInfo#getPropertyPath()} returns "sender.name"
+ * <p>{@link MatchInfo#getFullText()} returns "Test Name Jr."
+ * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 4]
+ * <p>{@link MatchInfo#getExactMatch()} returns "Test"
+ * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 9]
+ * <p>{@link MatchInfo#getSnippet()} returns "Test Name Jr."
+ * <p> Match-2
+ * <p>{@link MatchInfo#getPropertyPath()} returns "sender.email"
+ * <p>{@link MatchInfo#getFullText()} returns "TestNameJr@gmail.com"
+ * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 20]
+ * <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
+ * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
+ * <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
+ * @hide
+ */
+// TODO(sidchhabra): Capture real snippet after integration with icingLib.
+public final class MatchInfo {
+
+ private final String mPropertyPath;
+ private final SnippetMatchProto mSnippetMatch;
+ private final AppSearch.Document mDocument;
+ /**
+ * List of content with same property path in a document when there are multiple matches in
+ * repeated sections.
+ */
+ private final String[] mValues;
+
+ /** @hide */
+ public MatchInfo(@NonNull String propertyPath, @NonNull SnippetMatchProto snippetMatch,
+ @NonNull AppSearch.Document document) {
+ mPropertyPath = propertyPath;
+ mSnippetMatch = snippetMatch;
+ mDocument = document;
+ // In IcingLib snippeting is available for only 3 data types i.e String, double and long,
+ // so we need to check which of these three are requested.
+ // TODO (sidchhabra): getPropertyStringArray takes property name, handle for property path.
+ String[] values = mDocument.getPropertyStringArray(propertyPath);
+ if (values == null) {
+ values = doubleToString(mDocument.getPropertyDoubleArray(propertyPath));
+ }
+ if (values == null) {
+ values = longToString(mDocument.getPropertyLongArray(propertyPath));
+ }
+ if (values == null) {
+ throw new IllegalStateException("No content found for requested property path!");
+ }
+ mValues = values;
+ }
+
+ /**
+ * Gets the property path corresponding to the given entry.
+ * <p>Property Path: '.' - delimited sequence of property names indicating which property in
+ * the Document these snippets correspond to.
+ * <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc.
+ * For class example 1 this returns "subject"
+ */
+ @NonNull
+ public String getPropertyPath() {
+ return mPropertyPath;
+ }
+
+ /**
+ * Gets the full text corresponding to the given entry.
+ * <p>For class example this returns "A commonly used fake word is foo. Another nonsense word
+ * that’s used a lot is bar."
+ */
+ @NonNull
+ public String getFullText() {
+ return mValues[mSnippetMatch.getValuesIndex()];
+ }
+
+ /**
+ * Gets the exact match range corresponding to the given entry.
+ * <p>For class example 1 this returns [29, 32]
+ */
+ @NonNull
+ public Range getExactMatchPosition() {
+ return new Range(mSnippetMatch.getExactMatchPosition(),
+ mSnippetMatch.getExactMatchPosition() + mSnippetMatch.getExactMatchBytes());
+ }
+
+ /**
+ * Gets the exact match corresponding to the given entry.
+ * <p>For class example 1 this returns "foo"
+ */
+ @NonNull
+ public CharSequence getExactMatch() {
+ return getSubstring(getExactMatchPosition());
+ }
+
+ /**
+ * Gets the snippet range corresponding to the given entry.
+ * <p>For class example 1 this returns [29, 41]
+ */
+ @NonNull
+ public Range getSnippetPosition() {
+ return new Range(mSnippetMatch.getWindowPosition(),
+ mSnippetMatch.getWindowPosition() + mSnippetMatch.getWindowBytes());
+ }
+
+ /**
+ * Gets the snippet corresponding to the given entry.
+ * <p>Snippet - Provides a subset of the content to display. The
+ * length of this content can be changed {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
+ * Windowing is centered around the middle of the matched token with content on either side
+ * clipped to token boundaries.
+ * <p>For class example 1 this returns "foo. Another"
+ */
+ @NonNull
+ public CharSequence getSnippet() {
+ return getSubstring(getSnippetPosition());
+ }
+
+ private CharSequence getSubstring(Range range) {
+ return getFullText()
+ .substring((int) range.getLower(), (int) range.getUpper());
+ }
+
+ /** Utility method to convert double[] to String[] */
+ private String[] doubleToString(double[] values) {
+ //TODO(sidchhabra): Implement the method.
+ return null;
+ }
+
+ /** Utility method to convert long[] to String[] */
+ private String[] longToString(long[] values) {
+ //TODO(sidchhabra): Implement the method.
+ return null;
+ }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index d763103f1217..f48ebde288f3 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -17,27 +17,51 @@
package android.app.appsearch;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SnippetMatchProto;
+import com.google.android.icing.proto.SnippetProto;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* SearchResults are a list of results that are returned from a query. Each result from this
* list contains a document and may contain other fields like snippets based on request.
+ * This iterator class is not thread safe.
* @hide
*/
-public final class SearchResults {
+public final class SearchResults implements Iterator<SearchResults.Result> {
private final SearchResultProto mSearchResultProto;
+ private int mNextIdx;
/** @hide */
public SearchResults(SearchResultProto searchResultProto) {
mSearchResultProto = searchResultProto;
}
+ @Override
+ public boolean hasNext() {
+ return mNextIdx < mSearchResultProto.getResultsCount();
+ }
+
+ @NonNull
+ @Override
+ public Result next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ Result result = new Result(mSearchResultProto.getResults(mNextIdx));
+ mNextIdx++;
+ return result;
+ }
+
+
+
/**
* This class represents the result obtained from the query. It will contain the document which
* which matched the specified query string and specifications.
@@ -46,6 +70,9 @@ public final class SearchResults {
public static final class Result {
private final SearchResultProto.ResultProto mResultProto;
+ @Nullable
+ private AppSearch.Document mDocument;
+
private Result(SearchResultProto.ResultProto resultProto) {
mResultProto = resultProto;
}
@@ -55,35 +82,47 @@ public final class SearchResults {
* @return Document object which matched the query.
* @hide
*/
- // TODO(sidchhabra): Switch to Document constructor that takes proto.
@NonNull
public AppSearch.Document getDocument() {
- return AppSearch.Document.newBuilder(mResultProto.getDocument().getUri(),
- mResultProto.getDocument().getSchema())
- .setCreationTimestampMillis(mResultProto.getDocument().getCreationTimestampMs())
- .setScore(mResultProto.getDocument().getScore())
- .build();
+ if (mDocument == null) {
+ mDocument = new AppSearch.Document(mResultProto.getDocument());
+ }
+ return mDocument;
}
- // TODO(sidchhabra): Add Getter for ResultReader for Snippet.
+ /**
+ * Contains a list of Snippets that matched the request. Only populated when requested in
+ * {@link SearchSpec.Builder#setMaxSnippetSize(int)}.
+ * @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this
+ * method is called it will return {@code null}. Users can also restrict snippet population
+ * using {@link SearchSpec.Builder#setNumToSnippet} and
+ * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value
+ * this method will return {@code null}.
+ * @hide
+ */
+ // TODO(sidchhabra): Replace Document with proper constructor.
+ @Nullable
+ public List<MatchInfo> getMatchInfo() {
+ if (!mResultProto.hasSnippet()) {
+ return null;
+ }
+ AppSearch.Document document = getDocument();
+ List<MatchInfo> matchList = new ArrayList<>();
+ for (Iterator entryProtoIterator = mResultProto.getSnippet()
+ .getEntriesList().iterator(); entryProtoIterator.hasNext(); ) {
+ SnippetProto.EntryProto entry = (SnippetProto.EntryProto) entryProtoIterator.next();
+ for (Iterator snippetMatchProtoIterator = entry.getSnippetMatchesList().iterator();
+ snippetMatchProtoIterator.hasNext(); ) {
+ matchList.add(new MatchInfo(entry.getPropertyName(),
+ (SnippetMatchProto) snippetMatchProtoIterator.next(), document));
+ }
+ }
+ return matchList;
+ }
}
@Override
public String toString() {
return mSearchResultProto.toString();
}
-
- /**
- * Returns a {@link Result} iterator. Returns Empty Iterator if there are no matching results.
- * @hide
- */
- @NonNull
- public Iterator<Result> getResults() {
- List<Result> results = new ArrayList<>();
- // TODO(sidchhabra): Pass results using a RemoteStream.
- for (SearchResultProto.ResultProto resultProto : mSearchResultProto.getResultsList()) {
- results.add(new Result(resultProto));
- }
- return results.iterator();
- }
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
index 5df7108fec09..c276ae1fe45e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
@@ -19,25 +19,32 @@ package android.app.appsearch;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import com.google.android.icing.proto.ResultSpecProto;
+import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents the specification logic for AppSearch. It can be used to set the type of
* search, like prefix or exact only or apply filters to search for a specific schema type only etc.
* @hide
- *
*/
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
private final SearchSpecProto mSearchSpecProto;
+ private final ResultSpecProto mResultSpecProto;
+ private final ScoringSpecProto mScoringSpecProto;
- private SearchSpec(SearchSpecProto searchSpecProto) {
+ private SearchSpec(@NonNull SearchSpecProto searchSpecProto,
+ @NonNull ResultSpecProto resultSpecProto, @NonNull ScoringSpecProto scoringSpecProto) {
mSearchSpecProto = searchSpecProto;
+ mResultSpecProto = resultSpecProto;
+ mScoringSpecProto = scoringSpecProto;
}
/** Creates a new {@link SearchSpec.Builder}. */
@@ -48,10 +55,22 @@ public final class SearchSpec {
/** @hide */
@NonNull
- SearchSpecProto getProto() {
+ SearchSpecProto getSearchSpecProto() {
return mSearchSpecProto;
}
+ /** @hide */
+ @NonNull
+ ResultSpecProto getResultSpecProto() {
+ return mResultSpecProto;
+ }
+
+ /** @hide */
+ @NonNull
+ ScoringSpecProto getScoringSpecProto() {
+ return mScoringSpecProto;
+ }
+
/** Term Match Type for the query. */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
@@ -62,51 +81,164 @@ public final class SearchSpec {
@Retention(RetentionPolicy.SOURCE)
public @interface TermMatchTypeCode {}
+ /**
+ * Query terms will only match exact tokens in the index.
+ * <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
+ */
public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
+ /**
+ * Query terms will match indexed tokens when the query term is a prefix of the token.
+ * <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
+ */
public static final int TERM_MATCH_TYPE_PREFIX = 2;
+ /** Ranking Strategy for query result.*/
+ // NOTE: The integer values of these constants must match the proto enum constants in
+ // {@link ScoringSpecProto.RankingStrategy.Code }
+ @IntDef(prefix = {"RANKING_STRATEGY_"}, value = {
+ RANKING_STRATEGY_NONE,
+ RANKING_STRATEGY_DOCUMENT_SCORE,
+ RANKING_STRATEGY_CREATION_TIMESTAMP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RankingStrategyCode {}
+
+ /** No Ranking, results are returned in arbitrary order.*/
+ public static final int RANKING_STRATEGY_NONE = 0;
+ /** Ranked by app-provided document scores. */
+ public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1;
+ /** Ranked by document creation timestamps. */
+ public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
+
+ /** Order for query result.*/
+ // NOTE: The integer values of these constants must match the proto enum constants in
+ // {@link ScoringSpecProto.Order.Code }
+ @IntDef(prefix = {"ORDER_"}, value = {
+ ORDER_DESCENDING,
+ ORDER_ASCENDING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface OrderCode {}
+
+ /** Search results will be returned in a descending order. */
+ public static final int ORDER_DESCENDING = 0;
+ /** Search results will be returned in an ascending order. */
+ public static final int ORDER_ASCENDING = 1;
+
/** Builder for {@link SearchSpec objects}. */
public static final class Builder {
- private final SearchSpecProto.Builder mBuilder = SearchSpecProto.newBuilder();
+ private final SearchSpecProto.Builder mSearchSpecBuilder = SearchSpecProto.newBuilder();
+ private final ResultSpecProto.Builder mResultSpecBuilder = ResultSpecProto.newBuilder();
+ private final ScoringSpecProto.Builder mScoringSpecBuilder = ScoringSpecProto.newBuilder();
+ private final ResultSpecProto.SnippetSpecProto.Builder mSnippetSpecBuilder =
+ ResultSpecProto.SnippetSpecProto.newBuilder();
- private Builder(){}
+ private Builder() {
+ }
/**
* Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
- *
- * TermMatchType.Code=EXACT_ONLY
- * Query terms will only match exact tokens in the index.
- * Ex. A query term "foo" will only match indexed token "foo", and not "foot"
- * or "football"
- *
- * TermMatchType.Code=PREFIX
- * Query terms will match indexed tokens when the query term is a prefix of
- * the token.
- * Ex. A query term "foo" will match indexed tokens like "foo", "foot", and
- * "football".
*/
@NonNull
public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
TermMatchType.Code termMatchTypeCodeProto =
TermMatchType.Code.forNumber(termMatchTypeCode);
if (termMatchTypeCodeProto == null) {
- throw new IllegalArgumentException("Invalid term match type: " + termMatchTypeCode);
+ throw new IllegalArgumentException("Invalid term match type: "
+ + termMatchTypeCode);
}
- mBuilder.setTermMatchType(termMatchTypeCodeProto);
+ mSearchSpecBuilder.setTermMatchType(termMatchTypeCodeProto);
return this;
}
/**
- * Adds a Schema type filter to {@link SearchSpec} Entry.
- * Only search for documents that have the specified schema types.
- * If unset, the query will search over all schema types.
+ * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that
+ * have the specified schema types.
+ * <p>If unset, the query will search over all schema types.
*/
@NonNull
public Builder setSchemaTypes(@NonNull String... schemaTypes) {
for (String schemaType : schemaTypes) {
- mBuilder.addSchemaTypeFilters(schemaType);
+ mSearchSpecBuilder.addSchemaTypeFilters(schemaType);
+ }
+ return this;
+ }
+
+ /** Sets the maximum number of results to retrieve from the query */
+ @NonNull
+ public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) {
+ mResultSpecBuilder.setNumToRetrieve(numToRetrieve);
+ return this;
+ }
+
+ /** Sets ranking strategy for AppSearch results.*/
+ @NonNull
+ public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) {
+ ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
+ ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategy);
+ if (rankingStrategyCodeProto == null) {
+ throw new IllegalArgumentException("Invalid result ranking strategy: "
+ + rankingStrategyCodeProto);
}
+ mScoringSpecBuilder.setRankBy(rankingStrategyCodeProto);
+ return this;
+ }
+
+ /**
+ * Indicates the order of returned search results, the default is DESC, meaning that results
+ * with higher scores come first.
+ * <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}.
+ */
+ @NonNull
+ public Builder setOrder(@OrderCode int order) {
+ ScoringSpecProto.Order.Code orderCodeProto =
+ ScoringSpecProto.Order.Code.forNumber(order);
+ if (orderCodeProto == null) {
+ throw new IllegalArgumentException("Invalid result ranking order: "
+ + orderCodeProto);
+ }
+ mScoringSpecBuilder.setOrderBy(orderCodeProto);
+ return this;
+ }
+
+ /**
+ * Only the first {@code numToSnippet} documents based on the ranking strategy
+ * will have snippet information provided.
+ * <p>If set to 0 (default), snippeting is disabled and
+ * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
+ */
+ @NonNull
+ public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
+ mSnippetSpecBuilder.setNumToSnippet(numToSnippet);
+ return this;
+ }
+
+ /**
+ * Only the first {@code numMatchesPerProperty} matches for a every property of
+ * {@link AppSearchDocument} will contain snippet information.
+ * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
+ * will return {@code null} for that result.
+ */
+ @NonNull
+ public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
+ mSnippetSpecBuilder.setNumMatchesPerProperty(numMatchesPerProperty);
+ return this;
+ }
+
+ /**
+ * Sets {@code maxSnippetSize}, the maximum snippet size. Snippet windows start at
+ * {@code maxSnippetSize/2} bytes before the middle of the matching token and end at
+ * {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects
+ * token boundaries, therefore the returned window may be smaller than requested.
+ * <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will
+ * be returned. If matches enabled is also set to false, then snippeting is disabled.
+ * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
+ * return a window of "bar baz bat" which is only 11 bytes long.
+ */
+ @NonNull
+ public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
+ mSnippetSpecBuilder.setMaxWindowBytes(maxSnippetSize);
return this;
}
@@ -117,11 +249,12 @@ public final class SearchSpec {
*/
@NonNull
public SearchSpec build() {
- if (mBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) {
+ if (mSearchSpecBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) {
throw new IllegalSearchSpecException("Missing termMatchType field.");
}
- return new SearchSpec(mBuilder.build());
+ mResultSpecBuilder.setSnippetSpec(mSnippetSpecBuilder);
+ return new SearchSpec(mSearchSpecBuilder.build(), mResultSpecBuilder.build(),
+ mScoringSpecBuilder.build());
}
}
-
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index d2d9cf9fdf17..6293ee7059e5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -106,10 +106,11 @@ public class AppSearchManagerService extends SystemService {
// TODO(sidchhabra):Init FakeIcing properly.
// TODO(sidchhabra): Do this in a threadpool.
@Override
- public void query(@NonNull String queryExpression, @NonNull byte[] searchSpec,
- AndroidFuture callback) {
- Preconditions.checkNotNull(queryExpression);
+ public void query(@NonNull byte[] searchSpec, @NonNull byte[] resultSpec,
+ @NonNull byte[] scoringSpec, AndroidFuture callback) {
Preconditions.checkNotNull(searchSpec);
+ Preconditions.checkNotNull(resultSpec);
+ Preconditions.checkNotNull(scoringSpec);
SearchSpecProto searchSpecProto = null;
try {
searchSpecProto = SearchSpecProto.parseFrom(searchSpec);
@@ -117,7 +118,7 @@ public class AppSearchManagerService extends SystemService {
throw new RuntimeException(e);
}
SearchResultProto searchResults =
- mFakeIcing.query(queryExpression);
+ mFakeIcing.query(searchSpecProto.getQuery());
callback.complete(searchResults.toByteArray());
}
}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index 47af7c0a5ed9..756bc5ee14c7 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -37,11 +37,99 @@ import java.util.function.Consumer;
/**
* This class provides access to the blob store managed by the system.
*
- * Apps can publish data blobs which might be useful for other apps on the device to be
- * managed by the system and apps that would like to access these data blobs can do so
- * by addressing them via their cryptographically secure hashes.
+ * <p> Apps can publish and access a data blob using a {@link BlobHandle} object which can
+ * be created with {@link BlobHandle#createWithSha256(byte[], CharSequence, long, String)}.
+ * This {@link BlobHandle} object encapsulates the following pieces of information used for
+ * identifying the blobs:
+ * <ul>
+ * <li> {@link BlobHandle#getSha256Digest()}
+ * <li> {@link BlobHandle#getLabel()}
+ * <li> {@link BlobHandle#getExpiryTimeMillis()}
+ * <li> {@link BlobHandle#getTag()}
+ * </ul>
+ * For two {@link BlobHandle} objects to be considered identical, all these pieces of information
+ * must be equal.
*
- * TODO: More documentation.
+ * <p> For contributing a new data blob, an app needs to create a session using
+ * {@link BlobStoreManager#createSession(BlobHandle)} and then open this session for writing using
+ * {@link BlobStoreManager#openSession(long)}.
+ *
+ * <p> The following code snippet shows how to create and open a session for writing:
+ * <pre class="prettyprint">
+ * final long sessionId = blobStoreManager.createSession(blobHandle);
+ * try (BlobStoreManager.Session session = blobStoreManager.openSession(sessionId)) {
+ * try (ParcelFileDescriptor pfd = new ParcelFileDescriptor.AutoCloseOutputStream(
+ * session.openWrite(offsetBytes, lengthBytes))) {
+ * writeData(pfd);
+ * }
+ * }
+ * </pre>
+ *
+ * <p> If all the data could not be written in a single attempt, apps can close this session
+ * and re-open it again using the session id obtained via
+ * {@link BlobStoreManager#createSession(BlobHandle)}. Note that the session data is persisted
+ * and can be re-opened for completing the data contribution, even across device reboots.
+ *
+ * <p> After the data is written to the session, it can be committed using
+ * {@link Session#commit(Executor, Consumer)}. Until the session is committed, data written
+ * to the session will not be shared with any app.
+ *
+ * <p class="note"> Once a session is committed using {@link Session#commit(Executor, Consumer)},
+ * any data written as part of this session is sealed and cannot be modified anymore.
+ *
+ * <p> Before committing the session, apps can indicate which apps are allowed to access the
+ * contributed data using one or more of the following access modes:
+ * <ul>
+ * <li> {@link Session#allowPackageAccess(String, byte[])} which will allow whitelisting
+ * specific packages to access the blobs.
+ * <li> {@link Session#allowSameSignatureAccess()} which will allow only apps which are signed
+ * with the same certificate as the app which contributed the blob to access it.
+ * <li> {@link Session#allowPublicAccess()} which will allow any app on the device to access
+ * the blob.
+ * </ul>
+ *
+ * <p> The following code snippet shows how to specify the access mode and commit the session:
+ * <pre class="prettyprint">
+ * try (BlobStoreManager.Session session = blobStoreManager.openSession(sessionId)) {
+ * try (ParcelFileDescriptor pfd = new ParcelFileDescriptor.AutoCloseOutputStream(
+ * session.openWrite(offsetBytes, lengthBytes))) {
+ * writeData(pfd);
+ * }
+ * session.allowSameSignatureAccess();
+ * session.allowPackageAccess(packageName, certificate);
+ * session.commit(executor, callback);
+ * }
+ * </pre>
+ *
+ * <p> Apps that satisfy at least one of the access mode constraints specified by the publisher
+ * of the data blob will be able to access it.
+ *
+ * <p> A data blob published without specifying any of
+ * these access modes will be considered private and only the app that contributed the data
+ * blob will be allowed to access it. This is still useful for overall device system health as
+ * the System can try to keep one copy of data blob on disk when multiple apps contribute the
+ * same data.
+ *
+ * <p class="note"> It is strongly recommended that apps use one of
+ * {@link Session#allowPackageAccess(String, byte[])} or {@link Session#allowSameSignatureAccess()}
+ * when they know, ahead of time, the set of apps they would like to share the blobs with.
+ * {@link Session#allowPublicAccess()} is meant for publicly available data committed from
+ * libraries and SDKs.
+ *
+ * <p> Once a data blob is committed with {@link Session#commit(Executor, Consumer)}, it
+ * can be accessed using {@link BlobStoreManager#openBlob(BlobHandle)}, assuming the caller
+ * satisfies constraints of any of the access modes associated with that data blob. An app may
+ * acquire a lease on a blob with {@link BlobStoreManager#acquireLease(BlobHandle, int)} and
+ * release the lease with {@link BlobStoreManager#releaseLease(BlobHandle)}. A blob will not be
+ * deleted from the system while there is at least one app leasing it.
+ *
+ * <p> The following code snippet shows how to access the data blob:
+ * <pre class="prettyprint">
+ * try (ParcelFileDescriptor pfd = new ParcelFileDescriptor.AutoCloseInputStream(
+ * blobStoreManager.openBlob(blobHandle)) {
+ * useData(pfd);
+ * }
+ * </pre>
*/
@SystemService(Context.BLOB_STORE_SERVICE)
public class BlobStoreManager {
@@ -323,6 +411,28 @@ public class BlobStoreManager {
}
/**
+ * Opens a file descriptor to read the blob content already written into this session.
+ *
+ * @return a {@link ParcelFileDescriptor} for reading from the blob file.
+ *
+ * @throws IOException when there is an I/O error while opening the file to read.
+ * @throws SecurityException when the caller is not the owner of the session.
+ * @throws IllegalStateException when the caller tries to read the file after it is
+ * abandoned (using {@link #abandon()})
+ * or closed (using {@link #close()}).
+ */
+ public @NonNull ParcelFileDescriptor openRead() throws IOException {
+ try {
+ return mSession.openRead();
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets the size of the blob file that was written to the session so far.
*
* @return the size of the blob file so far.
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
index 4ae919bfedab..4035b96938d9 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl
@@ -21,6 +21,7 @@ import android.os.ParcelFileDescriptor;
/** {@hide} */
interface IBlobStoreSession {
ParcelFileDescriptor openWrite(long offsetBytes, long lengthBytes);
+ ParcelFileDescriptor openRead();
void allowPackageAccess(in String packageName, in byte[] certificate);
void allowSameSignatureAccess();
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 29092b327fc7..612fd89ebbe0 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -17,6 +17,7 @@ package com.android.server.blob;
import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR;
import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.SEEK_SET;
@@ -187,6 +188,40 @@ public class BlobStoreSession extends IBlobStoreSession.Stub {
}
@Override
+ @NonNull
+ public ParcelFileDescriptor openRead() {
+ assertCallerIsOwner();
+ synchronized (mSessionLock) {
+ if (mState != STATE_OPENED) {
+ throw new IllegalStateException("Not allowed to read in state: "
+ + stateToString(mState));
+ }
+
+ try {
+ return openReadLocked();
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
+ }
+ }
+
+ @GuardedBy("mSessionLock")
+ @NonNull
+ private ParcelFileDescriptor openReadLocked() throws IOException {
+ FileDescriptor fd = null;
+ try {
+ final File sessionFile = getSessionFile();
+ if (sessionFile == null) {
+ throw new IllegalStateException("Couldn't get the file for this session");
+ }
+ fd = Os.open(sessionFile.getPath(), O_RDONLY, 0);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+ return createRevocableFdLocked(fd);
+ }
+
+ @Override
@BytesLong
public long getSize() {
return 0;
diff --git a/apex/extservices/apex_manifest.json b/apex/extservices/apex_manifest.json
index 7ba21575df4a..b4acf1283d3e 100644
--- a/apex/extservices/apex_manifest.json
+++ b/apex/extservices/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.extservices",
- "version": 1
+ "version": 300000000
}
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
index 2a8c4f737dff..7960598affa3 100644
--- a/apex/permission/apex_manifest.json
+++ b/apex/permission/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.permission",
- "version": 1
+ "version": 300000000
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 51b911a94edc..1dbad456760c 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -18,6 +18,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ApexContext;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -48,6 +49,8 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
private static final String LOG_TAG = RuntimePermissionsPersistenceImpl.class.getSimpleName();
+ private static final String APEX_MODULE_NAME = "com.android.permission";
+
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
private static final String TAG_PACKAGE = "package";
@@ -253,9 +256,8 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers
@NonNull
private static File getFile(@NonNull UserHandle user) {
- // TODO: Use an API for this.
- File dataDirectory = new File("/data/misc_de/" + user.getIdentifier()
- + "/apexdata/com.android.permission");
+ ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
+ File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
}
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 5061742f4c58..06fad77c495c 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -18,6 +18,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ApexContext;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -50,6 +51,8 @@ public class RolesPersistenceImpl implements RolesPersistence {
private static final String LOG_TAG = RolesPersistenceImpl.class.getSimpleName();
+ private static final String APEX_MODULE_NAME = "com.android.permission";
+
private static final String ROLES_FILE_NAME = "roles.xml";
private static final String TAG_ROLES = "roles";
@@ -209,9 +212,8 @@ public class RolesPersistenceImpl implements RolesPersistence {
@NonNull
private static File getFile(@NonNull UserHandle user) {
- // TODO: Use an API for this.
- File dataDirectory = new File("/data/misc_de/" + user.getIdentifier()
- + "/apexdata/com.android.permission");
+ ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
+ File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, ROLES_FILE_NAME);
}
}
diff --git a/apex/sdkextensions/manifest.json b/apex/sdkextensions/manifest.json
index 048f5c4f177b..deeb29e155c0 100644
--- a/apex/sdkextensions/manifest.json
+++ b/apex/sdkextensions/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.sdkext",
- "version": 1
+ "version": 300000000
}
diff --git a/apex/statsd/apex_manifest.json b/apex/statsd/apex_manifest.json
index 0c0ad860f3d1..e2972e700880 100644
--- a/apex/statsd/apex_manifest.json
+++ b/apex/statsd/apex_manifest.json
@@ -1,5 +1,5 @@
{
"name": "com.android.os.statsd",
- "version": 1
+ "version": 300000000
}
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 0b46645ad06f..f66f0340edab 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -24,7 +24,7 @@ java_library {
name: "framework-statsd",
installable: true,
// TODO(b/146209659): Use system_current instead.
- sdk_version: "core_current",
+ sdk_version: "core_platform",
srcs: [
":framework-statsd-sources",
],
@@ -35,7 +35,9 @@ java_library {
libs: [
"framework-annotations-lib",
// TODO(b/146230220): Use framework-system-stubs instead.
- "android_system_stubs_current",
+ //"android_system_stubs_current",
+ //"framework_module_lib_stubs_current",
+ "framework-all",
],
hostdex: true, // for hiddenapi check
visibility: [
@@ -52,12 +54,14 @@ java_library {
droidstubs {
name: "framework-statsd-stubs-docs",
defaults: [
- "framework-module-stubs-defaults-publicapi"
+ "framework-module-stubs-defaults-systemapi"
],
srcs: [
+ ":framework-annotations",
":framework-statsd-sources",
],
libs: [
+ // TODO(b/148218250): Change to android_system_stubs_current
"framework-all",
],
sdk_version: "core_platform",
@@ -70,6 +74,7 @@ java_library {
":framework-statsd-stubs-docs",
],
libs: [
+ // TODO(b/148218250): Change to android_system_stubs_current
"framework-all",
],
sdk_version: "core_platform",
diff --git a/core/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 0ea05d8f683c..ad1ac95d667c 100644
--- a/core/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -30,7 +30,7 @@ import android.os.IPullAtomResultReceiver;
import android.os.IStatsManagerService;
import android.os.IStatsd;
import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.os.StatsFrameworkInitializer;
import android.util.AndroidException;
import android.util.Slog;
import android.util.StatsEvent;
@@ -702,7 +702,10 @@ public final class StatsManager {
return mStatsManagerService;
}
mStatsManagerService = IStatsManagerService.Stub.asInterface(
- ServiceManager.getService(Context.STATS_MANAGER_SERVICE));
+ StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsManagerServiceRegisterer()
+ .get());
return mStatsManagerService;
}
diff --git a/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java b/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java
new file mode 100644
index 000000000000..3d955336b45c
--- /dev/null
+++ b/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.StatsManager;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * Class for performing registration for all stats services
+ *
+ * TODO(b/148225705) Change to @SystemApi(client=MODULE_LIBRARIES) when the build system is ready.
+ * @hide
+ */
+@SystemApi
+public class StatsFrameworkInitializer {
+ private StatsFrameworkInitializer() {
+ }
+
+ private static volatile StatsServiceManager sStatsServiceManager;
+
+ /**
+ * Sets an instance of {@link StatsServiceManager} that allows
+ * the statsd mainline module to register/obtain stats binder services. This is called
+ * by the platform during the system initialization.
+ *
+ * @param statsServiceManager instance of {@link StatsServiceManager} that allows
+ * the statsd mainline module to register/obtain statsd binder services.
+ */
+ public static void setStatsServiceManager(
+ @NonNull StatsServiceManager statsServiceManager) {
+ if (sStatsServiceManager != null) {
+ throw new IllegalStateException("setStatsServiceManager called twice!");
+ }
+
+ if (statsServiceManager == null) {
+ throw new NullPointerException("statsServiceManager is null");
+ }
+
+ sStatsServiceManager = statsServiceManager;
+ }
+
+ /** @hide */
+ public static StatsServiceManager getStatsServiceManager() {
+ return sStatsServiceManager;
+ }
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers all statsd
+ * services to {@link Context}, so that {@link Context#getSystemService} can return them.
+ *
+ * @throws IllegalStateException if this is called from anywhere besides
+ * {@link SystemServiceRegistry}
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(
+ Context.STATS_MANAGER,
+ StatsManager.class,
+ context -> new StatsManager(context)
+ );
+ }
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index bcbb5a1407f6..4c8790f47bb6 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -85,6 +85,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StatsFrameworkInitializer;
import android.os.StatFs;
import android.os.StatsLogEventWrapper;
import android.os.SynchronousResultReceiver;
@@ -750,7 +751,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
* sStatsd with a null check.
*/
private static IStatsd fetchStatsdService() {
- return IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
+ return IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
}
/**
diff --git a/api/current.txt b/api/current.txt
index eb8ef8fa0190..056d8cab10f6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -333,6 +333,9 @@ package android {
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
field public static final int autofillHints = 16844118; // 0x1010556
+ field public static final int autofillInlineSuggestionChip = 16844307; // 0x1010613
+ field public static final int autofillInlineSuggestionSubtitle = 16844309; // 0x1010615
+ field public static final int autofillInlineSuggestionTitle = 16844308; // 0x1010614
field public static final int autofilledHighlight = 16844136; // 0x1010568
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
@@ -2253,6 +2256,7 @@ package android {
field public static final int ThemeOverlay_Material_Dialog = 16974550; // 0x10302d6
field public static final int ThemeOverlay_Material_Dialog_Alert = 16974551; // 0x10302d7
field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
+ field public static final int Theme_AutofillInlineSuggestion = 16974565; // 0x10302e5
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -6853,6 +6857,7 @@ package android.app.admin {
method @Nullable public java.util.List<java.lang.String> getPermittedAccessibilityServices(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
+ method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
method @NonNull public java.util.List<java.lang.String> getProtectedPackages(@NonNull android.content.ComponentName);
method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
@@ -6979,6 +6984,7 @@ package android.app.admin {
method public boolean setPermittedAccessibilityServices(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
+ method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
method public void setProfileEnabled(@NonNull android.content.ComponentName);
method public void setProfileName(@NonNull android.content.ComponentName, String);
method public void setProtectedPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
@@ -7014,6 +7020,7 @@ package android.app.admin {
field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
+ field public static final String ACTION_CHECK_POLICY_COMPLIANCE = "android.app.action.CHECK_POLICY_COMPLIANCE";
field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
@@ -7137,6 +7144,8 @@ package android.app.admin {
field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
+ field public static final int PERSONAL_APPS_NOT_SUSPENDED = 0; // 0x0
+ field public static final int PERSONAL_APPS_SUSPENDED_EXPLICITLY = 1; // 0x1
field public static final String POLICY_DISABLE_CAMERA = "policy_disable_camera";
field public static final String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
@@ -7538,6 +7547,7 @@ package android.app.blob {
method public boolean isPackageAccessAllowed(@NonNull String, @NonNull byte[]) throws java.io.IOException;
method public boolean isPublicAccessAllowed() throws java.io.IOException;
method public boolean isSameSignatureAccessAllowed() throws java.io.IOException;
+ method @NonNull public android.os.ParcelFileDescriptor openRead() throws java.io.IOException;
method @NonNull public android.os.ParcelFileDescriptor openWrite(long, long) throws java.io.IOException;
}
@@ -9965,6 +9975,7 @@ package android.content {
method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
method @NonNull public android.content.Context createFeatureContext(@Nullable String);
method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public android.content.Context createWindowContext(int);
method public abstract String[] databaseList();
method public abstract boolean deleteDatabase(String);
method public abstract boolean deleteFile(String);
@@ -9989,6 +10000,7 @@ package android.content {
method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(String);
method public abstract java.io.File getDir(String, int);
+ method @Nullable public android.view.Display getDisplay();
method @Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int);
method @Nullable public abstract java.io.File getExternalCacheDir();
method public abstract java.io.File[] getExternalCacheDirs();
@@ -10101,6 +10113,7 @@ package android.content {
field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final String CLIPBOARD_SERVICE = "clipboard";
field public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
+ field public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
field public static final String CONNECTIVITY_SERVICE = "connectivity";
field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -11770,6 +11783,7 @@ package android.content.pm {
method @Nullable public CharSequence getAppLabel();
method @Nullable public String getAppPackageName();
method @NonNull public int[] getChildSessionIds();
+ method public long getCreatedMillis();
method public int getInstallLocation();
method public int getInstallReason();
method @Nullable public String getInstallerPackageName();
@@ -12077,6 +12091,7 @@ package android.content.pm {
field public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
field @Deprecated public static final String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+ field public static final String FEATURE_VULKAN_DEQP_LEVEL = "android.software.vulkan.deqp.level";
field public static final String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
field public static final String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
field public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
@@ -13515,227 +13530,227 @@ package android.database.sqlite {
package android.drm {
- public class DrmConvertedStatus {
- ctor public DrmConvertedStatus(int, byte[], int);
- field public static final int STATUS_ERROR = 3; // 0x3
- field public static final int STATUS_INPUTDATA_ERROR = 2; // 0x2
- field public static final int STATUS_OK = 1; // 0x1
- field public final byte[] convertedData;
- field public final int offset;
- field public final int statusCode;
- }
-
- public class DrmErrorEvent extends android.drm.DrmEvent {
- ctor public DrmErrorEvent(int, int, String);
- ctor public DrmErrorEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
- field public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008; // 0x7d8
- field public static final int TYPE_NOT_SUPPORTED = 2003; // 0x7d3
- field public static final int TYPE_NO_INTERNET_CONNECTION = 2005; // 0x7d5
- field public static final int TYPE_OUT_OF_MEMORY = 2004; // 0x7d4
- field public static final int TYPE_PROCESS_DRM_INFO_FAILED = 2006; // 0x7d6
- field public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007; // 0x7d7
- field public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001; // 0x7d1
- field public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002; // 0x7d2
- }
-
- public class DrmEvent {
- ctor protected DrmEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
- ctor protected DrmEvent(int, int, String);
- method public Object getAttribute(String);
- method public String getMessage();
- method public int getType();
- method public int getUniqueId();
- field public static final String DRM_INFO_OBJECT = "drm_info_object";
- field public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
- field public static final int TYPE_ALL_RIGHTS_REMOVED = 1001; // 0x3e9
- field public static final int TYPE_DRM_INFO_PROCESSED = 1002; // 0x3ea
- }
-
- public class DrmInfo {
- ctor public DrmInfo(int, byte[], String);
- ctor public DrmInfo(int, String, String);
- method public Object get(String);
- method public byte[] getData();
- method public int getInfoType();
- method public String getMimeType();
- method public java.util.Iterator<java.lang.Object> iterator();
- method public java.util.Iterator<java.lang.String> keyIterator();
- method public void put(String, Object);
- }
-
- public class DrmInfoEvent extends android.drm.DrmEvent {
- ctor public DrmInfoEvent(int, int, String);
- ctor public DrmInfoEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
- field public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5; // 0x5
- field public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1; // 0x1
- field public static final int TYPE_REMOVE_RIGHTS = 2; // 0x2
- field public static final int TYPE_RIGHTS_INSTALLED = 3; // 0x3
- field public static final int TYPE_RIGHTS_REMOVED = 6; // 0x6
- field public static final int TYPE_WAIT_FOR_RIGHTS = 4; // 0x4
- }
-
- public class DrmInfoRequest {
- ctor public DrmInfoRequest(int, String);
- method public Object get(String);
- method public int getInfoType();
- method public String getMimeType();
- method public java.util.Iterator<java.lang.Object> iterator();
- method public java.util.Iterator<java.lang.String> keyIterator();
- method public void put(String, Object);
- field public static final String ACCOUNT_ID = "account_id";
- field public static final String SUBSCRIPTION_ID = "subscription_id";
- field public static final int TYPE_REGISTRATION_INFO = 1; // 0x1
- field public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3; // 0x3
- field public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4; // 0x4
- field public static final int TYPE_UNREGISTRATION_INFO = 2; // 0x2
- }
-
- public class DrmInfoStatus {
- ctor public DrmInfoStatus(int, int, android.drm.ProcessedData, String);
- field public static final int STATUS_ERROR = 2; // 0x2
- field public static final int STATUS_OK = 1; // 0x1
- field public final android.drm.ProcessedData data;
- field public final int infoType;
- field public final String mimeType;
- field public final int statusCode;
- }
-
- public class DrmManagerClient implements java.lang.AutoCloseable {
- ctor public DrmManagerClient(android.content.Context);
- method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
- method public int acquireRights(android.drm.DrmInfoRequest);
- method public boolean canHandle(String, String);
- method public boolean canHandle(android.net.Uri, String);
- method public int checkRightsStatus(String);
- method public int checkRightsStatus(android.net.Uri);
- method public int checkRightsStatus(String, int);
- method public int checkRightsStatus(android.net.Uri, int);
- method public void close();
- method public android.drm.DrmConvertedStatus closeConvertSession(int);
- method public android.drm.DrmConvertedStatus convertData(int, byte[]);
- method public String[] getAvailableDrmEngines();
- method @NonNull public java.util.Collection<android.drm.DrmSupportInfo> getAvailableDrmSupportInfo();
- method public android.content.ContentValues getConstraints(String, int);
- method public android.content.ContentValues getConstraints(android.net.Uri, int);
- method public int getDrmObjectType(String, String);
- method public int getDrmObjectType(android.net.Uri, String);
- method public android.content.ContentValues getMetadata(String);
- method public android.content.ContentValues getMetadata(android.net.Uri);
- method public String getOriginalMimeType(String);
- method public String getOriginalMimeType(android.net.Uri);
- method public int openConvertSession(String);
- method public int processDrmInfo(android.drm.DrmInfo);
+ @Deprecated public class DrmConvertedStatus {
+ ctor @Deprecated public DrmConvertedStatus(int, byte[], int);
+ field @Deprecated public static final int STATUS_ERROR = 3; // 0x3
+ field @Deprecated public static final int STATUS_INPUTDATA_ERROR = 2; // 0x2
+ field @Deprecated public static final int STATUS_OK = 1; // 0x1
+ field @Deprecated public final byte[] convertedData;
+ field @Deprecated public final int offset;
+ field @Deprecated public final int statusCode;
+ }
+
+ @Deprecated public class DrmErrorEvent extends android.drm.DrmEvent {
+ ctor @Deprecated public DrmErrorEvent(int, int, String);
+ ctor @Deprecated public DrmErrorEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
+ field @Deprecated public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008; // 0x7d8
+ field @Deprecated public static final int TYPE_NOT_SUPPORTED = 2003; // 0x7d3
+ field @Deprecated public static final int TYPE_NO_INTERNET_CONNECTION = 2005; // 0x7d5
+ field @Deprecated public static final int TYPE_OUT_OF_MEMORY = 2004; // 0x7d4
+ field @Deprecated public static final int TYPE_PROCESS_DRM_INFO_FAILED = 2006; // 0x7d6
+ field @Deprecated public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007; // 0x7d7
+ field @Deprecated public static final int TYPE_RIGHTS_NOT_INSTALLED = 2001; // 0x7d1
+ field @Deprecated public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 2002; // 0x7d2
+ }
+
+ @Deprecated public class DrmEvent {
+ ctor @Deprecated protected DrmEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
+ ctor @Deprecated protected DrmEvent(int, int, String);
+ method @Deprecated public Object getAttribute(String);
+ method @Deprecated public String getMessage();
+ method @Deprecated public int getType();
+ method @Deprecated public int getUniqueId();
+ field @Deprecated public static final String DRM_INFO_OBJECT = "drm_info_object";
+ field @Deprecated public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+ field @Deprecated public static final int TYPE_ALL_RIGHTS_REMOVED = 1001; // 0x3e9
+ field @Deprecated public static final int TYPE_DRM_INFO_PROCESSED = 1002; // 0x3ea
+ }
+
+ @Deprecated public class DrmInfo {
+ ctor @Deprecated public DrmInfo(int, byte[], String);
+ ctor @Deprecated public DrmInfo(int, String, String);
+ method @Deprecated public Object get(String);
+ method @Deprecated public byte[] getData();
+ method @Deprecated public int getInfoType();
+ method @Deprecated public String getMimeType();
+ method @Deprecated public java.util.Iterator<java.lang.Object> iterator();
+ method @Deprecated public java.util.Iterator<java.lang.String> keyIterator();
+ method @Deprecated public void put(String, Object);
+ }
+
+ @Deprecated public class DrmInfoEvent extends android.drm.DrmEvent {
+ ctor @Deprecated public DrmInfoEvent(int, int, String);
+ ctor @Deprecated public DrmInfoEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
+ field @Deprecated public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5; // 0x5
+ field @Deprecated public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1; // 0x1
+ field @Deprecated public static final int TYPE_REMOVE_RIGHTS = 2; // 0x2
+ field @Deprecated public static final int TYPE_RIGHTS_INSTALLED = 3; // 0x3
+ field @Deprecated public static final int TYPE_RIGHTS_REMOVED = 6; // 0x6
+ field @Deprecated public static final int TYPE_WAIT_FOR_RIGHTS = 4; // 0x4
+ }
+
+ @Deprecated public class DrmInfoRequest {
+ ctor @Deprecated public DrmInfoRequest(int, String);
+ method @Deprecated public Object get(String);
+ method @Deprecated public int getInfoType();
+ method @Deprecated public String getMimeType();
+ method @Deprecated public java.util.Iterator<java.lang.Object> iterator();
+ method @Deprecated public java.util.Iterator<java.lang.String> keyIterator();
+ method @Deprecated public void put(String, Object);
+ field @Deprecated public static final String ACCOUNT_ID = "account_id";
+ field @Deprecated public static final String SUBSCRIPTION_ID = "subscription_id";
+ field @Deprecated public static final int TYPE_REGISTRATION_INFO = 1; // 0x1
+ field @Deprecated public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3; // 0x3
+ field @Deprecated public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4; // 0x4
+ field @Deprecated public static final int TYPE_UNREGISTRATION_INFO = 2; // 0x2
+ }
+
+ @Deprecated public class DrmInfoStatus {
+ ctor @Deprecated public DrmInfoStatus(int, int, android.drm.ProcessedData, String);
+ field @Deprecated public static final int STATUS_ERROR = 2; // 0x2
+ field @Deprecated public static final int STATUS_OK = 1; // 0x1
+ field @Deprecated public final android.drm.ProcessedData data;
+ field @Deprecated public final int infoType;
+ field @Deprecated public final String mimeType;
+ field @Deprecated public final int statusCode;
+ }
+
+ @Deprecated public class DrmManagerClient implements java.lang.AutoCloseable {
+ ctor @Deprecated public DrmManagerClient(android.content.Context);
+ method @Deprecated public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
+ method @Deprecated public int acquireRights(android.drm.DrmInfoRequest);
+ method @Deprecated public boolean canHandle(String, String);
+ method @Deprecated public boolean canHandle(android.net.Uri, String);
+ method @Deprecated public int checkRightsStatus(String);
+ method @Deprecated public int checkRightsStatus(android.net.Uri);
+ method @Deprecated public int checkRightsStatus(String, int);
+ method @Deprecated public int checkRightsStatus(android.net.Uri, int);
+ method @Deprecated public void close();
+ method @Deprecated public android.drm.DrmConvertedStatus closeConvertSession(int);
+ method @Deprecated public android.drm.DrmConvertedStatus convertData(int, byte[]);
+ method @Deprecated public String[] getAvailableDrmEngines();
+ method @Deprecated @NonNull public java.util.Collection<android.drm.DrmSupportInfo> getAvailableDrmSupportInfo();
+ method @Deprecated public android.content.ContentValues getConstraints(String, int);
+ method @Deprecated public android.content.ContentValues getConstraints(android.net.Uri, int);
+ method @Deprecated public int getDrmObjectType(String, String);
+ method @Deprecated public int getDrmObjectType(android.net.Uri, String);
+ method @Deprecated public android.content.ContentValues getMetadata(String);
+ method @Deprecated public android.content.ContentValues getMetadata(android.net.Uri);
+ method @Deprecated public String getOriginalMimeType(String);
+ method @Deprecated public String getOriginalMimeType(android.net.Uri);
+ method @Deprecated public int openConvertSession(String);
+ method @Deprecated public int processDrmInfo(android.drm.DrmInfo);
method @Deprecated public void release();
- method public int removeAllRights();
- method public int removeRights(String);
- method public int removeRights(android.net.Uri);
- method public int saveRights(android.drm.DrmRights, String, String) throws java.io.IOException;
- method public void setOnErrorListener(android.drm.DrmManagerClient.OnErrorListener);
- method public void setOnEventListener(android.drm.DrmManagerClient.OnEventListener);
- method public void setOnInfoListener(android.drm.DrmManagerClient.OnInfoListener);
- field public static final int ERROR_NONE = 0; // 0x0
- field public static final int ERROR_UNKNOWN = -2000; // 0xfffff830
+ method @Deprecated public int removeAllRights();
+ method @Deprecated public int removeRights(String);
+ method @Deprecated public int removeRights(android.net.Uri);
+ method @Deprecated public int saveRights(android.drm.DrmRights, String, String) throws java.io.IOException;
+ method @Deprecated public void setOnErrorListener(android.drm.DrmManagerClient.OnErrorListener);
+ method @Deprecated public void setOnEventListener(android.drm.DrmManagerClient.OnEventListener);
+ method @Deprecated public void setOnInfoListener(android.drm.DrmManagerClient.OnInfoListener);
+ field @Deprecated public static final int ERROR_NONE = 0; // 0x0
+ field @Deprecated public static final int ERROR_UNKNOWN = -2000; // 0xfffff830
}
- public static interface DrmManagerClient.OnErrorListener {
- method public void onError(android.drm.DrmManagerClient, android.drm.DrmErrorEvent);
+ @Deprecated public static interface DrmManagerClient.OnErrorListener {
+ method @Deprecated public void onError(android.drm.DrmManagerClient, android.drm.DrmErrorEvent);
}
- public static interface DrmManagerClient.OnEventListener {
- method public void onEvent(android.drm.DrmManagerClient, android.drm.DrmEvent);
+ @Deprecated public static interface DrmManagerClient.OnEventListener {
+ method @Deprecated public void onEvent(android.drm.DrmManagerClient, android.drm.DrmEvent);
}
- public static interface DrmManagerClient.OnInfoListener {
- method public void onInfo(android.drm.DrmManagerClient, android.drm.DrmInfoEvent);
+ @Deprecated public static interface DrmManagerClient.OnInfoListener {
+ method @Deprecated public void onInfo(android.drm.DrmManagerClient, android.drm.DrmInfoEvent);
}
- public class DrmRights {
- ctor public DrmRights(String, String);
- ctor public DrmRights(String, String, String);
- ctor public DrmRights(String, String, String, String);
- ctor public DrmRights(java.io.File, String);
- ctor public DrmRights(android.drm.ProcessedData, String);
- method public String getAccountId();
- method public byte[] getData();
- method public String getMimeType();
- method public String getSubscriptionId();
+ @Deprecated public class DrmRights {
+ ctor @Deprecated public DrmRights(String, String);
+ ctor @Deprecated public DrmRights(String, String, String);
+ ctor @Deprecated public DrmRights(String, String, String, String);
+ ctor @Deprecated public DrmRights(java.io.File, String);
+ ctor @Deprecated public DrmRights(android.drm.ProcessedData, String);
+ method @Deprecated public String getAccountId();
+ method @Deprecated public byte[] getData();
+ method @Deprecated public String getMimeType();
+ method @Deprecated public String getSubscriptionId();
}
- public class DrmStore {
+ @Deprecated public class DrmStore {
ctor @Deprecated public DrmStore();
}
- public static class DrmStore.Action {
+ @Deprecated public static class DrmStore.Action {
ctor @Deprecated public DrmStore.Action();
- field public static final int DEFAULT = 0; // 0x0
- field public static final int DISPLAY = 7; // 0x7
- field public static final int EXECUTE = 6; // 0x6
- field public static final int OUTPUT = 4; // 0x4
- field public static final int PLAY = 1; // 0x1
- field public static final int PREVIEW = 5; // 0x5
- field public static final int RINGTONE = 2; // 0x2
- field public static final int TRANSFER = 3; // 0x3
- }
-
- public static interface DrmStore.ConstraintsColumns {
- field public static final String EXTENDED_METADATA = "extended_metadata";
- field public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
- field public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
- field public static final String LICENSE_START_TIME = "license_start_time";
- field public static final String MAX_REPEAT_COUNT = "max_repeat_count";
- field public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
- }
-
- public static class DrmStore.DrmObjectType {
+ field @Deprecated public static final int DEFAULT = 0; // 0x0
+ field @Deprecated public static final int DISPLAY = 7; // 0x7
+ field @Deprecated public static final int EXECUTE = 6; // 0x6
+ field @Deprecated public static final int OUTPUT = 4; // 0x4
+ field @Deprecated public static final int PLAY = 1; // 0x1
+ field @Deprecated public static final int PREVIEW = 5; // 0x5
+ field @Deprecated public static final int RINGTONE = 2; // 0x2
+ field @Deprecated public static final int TRANSFER = 3; // 0x3
+ }
+
+ @Deprecated public static interface DrmStore.ConstraintsColumns {
+ field @Deprecated public static final String EXTENDED_METADATA = "extended_metadata";
+ field @Deprecated public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
+ field @Deprecated public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
+ field @Deprecated public static final String LICENSE_START_TIME = "license_start_time";
+ field @Deprecated public static final String MAX_REPEAT_COUNT = "max_repeat_count";
+ field @Deprecated public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
+ }
+
+ @Deprecated public static class DrmStore.DrmObjectType {
ctor @Deprecated public DrmStore.DrmObjectType();
- field public static final int CONTENT = 1; // 0x1
- field public static final int RIGHTS_OBJECT = 2; // 0x2
- field public static final int TRIGGER_OBJECT = 3; // 0x3
- field public static final int UNKNOWN = 0; // 0x0
+ field @Deprecated public static final int CONTENT = 1; // 0x1
+ field @Deprecated public static final int RIGHTS_OBJECT = 2; // 0x2
+ field @Deprecated public static final int TRIGGER_OBJECT = 3; // 0x3
+ field @Deprecated public static final int UNKNOWN = 0; // 0x0
}
- public static class DrmStore.Playback {
+ @Deprecated public static class DrmStore.Playback {
ctor @Deprecated public DrmStore.Playback();
- field public static final int PAUSE = 2; // 0x2
- field public static final int RESUME = 3; // 0x3
- field public static final int START = 0; // 0x0
- field public static final int STOP = 1; // 0x1
+ field @Deprecated public static final int PAUSE = 2; // 0x2
+ field @Deprecated public static final int RESUME = 3; // 0x3
+ field @Deprecated public static final int START = 0; // 0x0
+ field @Deprecated public static final int STOP = 1; // 0x1
}
- public static class DrmStore.RightsStatus {
+ @Deprecated public static class DrmStore.RightsStatus {
ctor @Deprecated public DrmStore.RightsStatus();
- field public static final int RIGHTS_EXPIRED = 2; // 0x2
- field public static final int RIGHTS_INVALID = 1; // 0x1
- field public static final int RIGHTS_NOT_ACQUIRED = 3; // 0x3
- field public static final int RIGHTS_VALID = 0; // 0x0
+ field @Deprecated public static final int RIGHTS_EXPIRED = 2; // 0x2
+ field @Deprecated public static final int RIGHTS_INVALID = 1; // 0x1
+ field @Deprecated public static final int RIGHTS_NOT_ACQUIRED = 3; // 0x3
+ field @Deprecated public static final int RIGHTS_VALID = 0; // 0x0
}
- public class DrmSupportInfo {
- ctor public DrmSupportInfo();
- method public void addFileSuffix(String);
- method public void addMimeType(String);
+ @Deprecated public class DrmSupportInfo {
+ ctor @Deprecated public DrmSupportInfo();
+ method @Deprecated public void addFileSuffix(String);
+ method @Deprecated public void addMimeType(String);
method @Deprecated public String getDescriprition();
- method public String getDescription();
- method public java.util.Iterator<java.lang.String> getFileSuffixIterator();
- method public java.util.Iterator<java.lang.String> getMimeTypeIterator();
- method public void setDescription(String);
+ method @Deprecated public String getDescription();
+ method @Deprecated public java.util.Iterator<java.lang.String> getFileSuffixIterator();
+ method @Deprecated public java.util.Iterator<java.lang.String> getMimeTypeIterator();
+ method @Deprecated public void setDescription(String);
}
- public class DrmUtils {
- ctor public DrmUtils();
- method public static android.drm.DrmUtils.ExtendedMetadataParser getExtendedMetadataParser(byte[]);
+ @Deprecated public class DrmUtils {
+ ctor @Deprecated public DrmUtils();
+ method @Deprecated public static android.drm.DrmUtils.ExtendedMetadataParser getExtendedMetadataParser(byte[]);
}
- public static class DrmUtils.ExtendedMetadataParser {
- method public String get(String);
- method public java.util.Iterator<java.lang.String> iterator();
- method public java.util.Iterator<java.lang.String> keyIterator();
+ @Deprecated public static class DrmUtils.ExtendedMetadataParser {
+ method @Deprecated public String get(String);
+ method @Deprecated public java.util.Iterator<java.lang.String> iterator();
+ method @Deprecated public java.util.Iterator<java.lang.String> keyIterator();
}
- public class ProcessedData {
- method public String getAccountId();
- method public byte[] getData();
- method public String getSubscriptionId();
+ @Deprecated public class ProcessedData {
+ method @Deprecated public String getAccountId();
+ method @Deprecated public byte[] getData();
+ method @Deprecated public String getSubscriptionId();
}
}
@@ -17249,6 +17264,8 @@ package android.hardware.camera2 {
method public void onCameraAccessPrioritiesChanged();
method public void onCameraAvailable(@NonNull String);
method public void onCameraUnavailable(@NonNull String);
+ method public void onPhysicalCameraAvailable(@NonNull String, @NonNull String);
+ method public void onPhysicalCameraUnavailable(@NonNull String, @NonNull String);
}
public abstract static class CameraManager.TorchCallback {
@@ -23380,6 +23397,9 @@ package android.location {
method public long getFullBiasNanos();
method public int getHardwareClockDiscontinuityCount();
method public int getLeapSecond();
+ method @FloatRange(from=0.0) public double getReferenceCarrierFrequencyHzForIsb();
+ method @NonNull public String getReferenceCodeTypeForIsb();
+ method public int getReferenceConstellationTypeForIsb();
method public long getTimeNanos();
method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
method public boolean hasBiasNanos();
@@ -23390,6 +23410,9 @@ package android.location {
method public boolean hasElapsedRealtimeUncertaintyNanos();
method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
+ method public boolean hasReferenceCarrierFrequencyHzForIsb();
+ method public boolean hasReferenceCodeTypeForIsb();
+ method public boolean hasReferenceConstellationTypeForIsb();
method public boolean hasTimeUncertaintyNanos();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
@@ -23414,6 +23437,10 @@ package android.location {
method public double getPseudorangeRateUncertaintyMetersPerSecond();
method public long getReceivedSvTimeNanos();
method public long getReceivedSvTimeUncertaintyNanos();
+ method public double getReceiverInterSignalBiasNanos();
+ method @FloatRange(from=0.0) public double getReceiverInterSignalBiasUncertaintyNanos();
+ method public double getSatelliteInterSignalBiasNanos();
+ method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
method public double getSnrInDb();
method public int getState();
method public int getSvid();
@@ -23425,6 +23452,10 @@ package android.location {
method @Deprecated public boolean hasCarrierPhase();
method @Deprecated public boolean hasCarrierPhaseUncertainty();
method public boolean hasCodeType();
+ method public boolean hasReceiverInterSignalBiasNanos();
+ method public boolean hasReceiverInterSignalBiasUncertaintyNanos();
+ method public boolean hasSatelliteInterSignalBiasNanos();
+ method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
method public boolean hasSnrInDb();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
@@ -23828,6 +23859,8 @@ package android.media {
method @NonNull public int[] getChannelCounts();
method @NonNull public int[] getChannelIndexMasks();
method @NonNull public int[] getChannelMasks();
+ method @NonNull public int[] getEncapsulationMetadataTypes();
+ method @NonNull public int[] getEncapsulationModes();
method @NonNull public int[] getEncodings();
method public int getId();
method public CharSequence getProductName();
@@ -24185,8 +24218,10 @@ package android.media {
public final class AudioPlaybackCaptureConfiguration {
method @NonNull public int[] getExcludeUids();
method @NonNull public int[] getExcludeUsages();
+ method @NonNull public int[] getExcludeUserIds();
method @NonNull public int[] getMatchingUids();
method @NonNull public int[] getMatchingUsages();
+ method @NonNull public int[] getMatchingUserIds();
method @NonNull public android.media.projection.MediaProjection getMediaProjection();
}
@@ -24194,9 +24229,11 @@ package android.media {
ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(int);
+ method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUserId(int);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration build();
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(int);
+ method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUserId(int);
}
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
@@ -24448,6 +24485,8 @@ package android.media {
field public static final int DUAL_MONO_MODE_LR = 1; // 0x1
field public static final int DUAL_MONO_MODE_OFF = 0; // 0x0
field public static final int DUAL_MONO_MODE_RR = 3; // 0x3
+ field public static final int ENCAPSULATION_METADATA_TYPE_DVB_AD_DESCRIPTOR = 2; // 0x2
+ field public static final int ENCAPSULATION_METADATA_TYPE_FRAMEWORK_TUNER = 1; // 0x1
field public static final int ENCAPSULATION_MODE_ELEMENTARY_STREAM = 1; // 0x1
field public static final int ENCAPSULATION_MODE_HANDLE = 2; // 0x2
field public static final int ENCAPSULATION_MODE_NONE = 0; // 0x0
@@ -27616,6 +27655,8 @@ package android.media.audiofx {
field public static final int CONTENT_TYPE_VOICE = 3; // 0x3
field public static final String EFFECT_AUXILIARY = "Auxiliary";
field public static final String EFFECT_INSERT = "Insert";
+ field public static final String EFFECT_POST_PROCESSING = "Post Processing";
+ field public static final String EFFECT_PRE_PROCESSING = "Pre Processing";
field public static final java.util.UUID EFFECT_TYPE_AEC;
field public static final java.util.UUID EFFECT_TYPE_AGC;
field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
@@ -29547,8 +29588,6 @@ package android.net {
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 {
@@ -29558,21 +29597,29 @@ package android.net {
method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
}
- public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+ public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
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;
+ method public int describeContents();
+ method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
}
- public static class ConnectivityDiagnosticsManager.DataStallReport {
+ public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
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;
+ method public int describeContents();
+ method public int getDetectionMethod();
+ method @NonNull public android.net.Network getNetwork();
+ method public long getReportTimestamp();
+ method @NonNull public android.os.PersistableBundle getStallDetails();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
}
public class ConnectivityManager {
@@ -31070,7 +31117,7 @@ package android.net.wifi {
method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public void addSuggestionConnectionStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
method @Deprecated public static int calculateSignalLevel(int, int);
- method public int calculateSignalLevel(int);
+ method @IntRange(from=0) public int calculateSignalLevel(int);
method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(String);
@@ -31083,7 +31130,7 @@ package android.net.wifi {
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public int getMaxNumberOfNetworkSuggestionsPerApp();
- method public int getMaxSignalLevel();
+ method @IntRange(from=0) public int getMaxSignalLevel();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
@@ -42725,6 +42772,7 @@ package android.service.autofill {
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
+ method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlinePresentation);
method @NonNull public android.service.autofill.FillResponse build();
method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
@@ -42754,10 +42802,11 @@ package android.service.autofill {
}
public final class InlinePresentation implements android.os.Parcelable {
- ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec);
+ ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean);
method public int describeContents();
method @NonNull public android.view.inline.InlinePresentationSpec getInlinePresentationSpec();
method @NonNull public android.app.slice.Slice getSlice();
+ method public boolean isPinned();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.InlinePresentation> CREATOR;
}
@@ -43524,7 +43573,7 @@ package android.service.voice {
field public static final int STATE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
field public static final int STATE_KEYPHRASE_ENROLLED = 2; // 0x2
field public static final int STATE_KEYPHRASE_UNENROLLED = 1; // 0x1
- field public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
+ field @Deprecated public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
}
public abstract static class AlwaysOnHotwordDetector.Callback {
@@ -46126,6 +46175,7 @@ package android.telephony {
field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+ field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool";
field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool";
field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
@@ -46172,6 +46222,15 @@ package android.telephony {
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
+ public static final class CarrierConfigManager.Apn {
+ field public static final String KEY_PREFIX = "apn.";
+ field public static final String KEY_SETTINGS_DEFAULT_PROTOCOL_STRING = "apn.settings_default_protocol_string";
+ field public static final String KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING = "apn.settings_default_roaming_protocol_string";
+ field public static final String PROTOCOL_IPV4 = "IP";
+ field public static final String PROTOCOL_IPV4V6 = "IPV4V6";
+ field public static final String PROTOCOL_IPV6 = "IPV6";
+ }
+
public static final class CarrierConfigManager.Gps {
field public static final String KEY_PERSIST_LPP_MODE_BOOL = "gps.persist_lpp_mode_bool";
field public static final String KEY_PREFIX = "gps.";
@@ -46271,6 +46330,7 @@ package android.telephony {
public final class CellIdentityLte extends android.telephony.CellIdentity {
method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
+ method @NonNull public java.util.List<java.lang.Integer> getBands();
method public int getBandwidth();
method public int getCi();
method @Nullable public android.telephony.ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo();
@@ -46288,7 +46348,7 @@ package android.telephony {
public final class CellIdentityNr extends android.telephony.CellIdentity {
method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
- method public int getBand();
+ method @NonNull public java.util.List<java.lang.Integer> getBands();
method @Nullable public String getMccString();
method @Nullable public String getMncString();
method public long getNci();
@@ -47209,6 +47269,7 @@ package android.telephony {
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei();
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public String getManualNetworkSelectionPlmn();
method @Nullable public String getManufacturerCode();
method @Nullable public String getManufacturerCode(int);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid();
@@ -47264,6 +47325,7 @@ package android.telephony {
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRttSupported();
@@ -47672,10 +47734,42 @@ package android.telephony.euicc {
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
+ field public static final int ERROR_ADDRESS_MISSING = 10011; // 0x271b
+ field public static final int ERROR_CARRIER_LOCKED = 10000; // 0x2710
+ field public static final int ERROR_CERTIFICATE_ERROR = 10012; // 0x271c
+ field public static final int ERROR_CONNECTION_ERROR = 10014; // 0x271e
+ field public static final int ERROR_DISALLOWED_BY_PPR = 10010; // 0x271a
+ field public static final int ERROR_EUICC_INSUFFICIENT_MEMORY = 10004; // 0x2714
+ field public static final int ERROR_EUICC_MISSING = 10006; // 0x2716
+ field public static final int ERROR_INCOMPATIBLE_CARRIER = 10003; // 0x2713
+ field public static final int ERROR_INSTALL_PROFILE = 10009; // 0x2719
+ field public static final int ERROR_INVALID_ACTIVATION_CODE = 10001; // 0x2711
+ field public static final int ERROR_INVALID_CONFIRMATION_CODE = 10002; // 0x2712
+ field public static final int ERROR_INVALID_RESPONSE = 10015; // 0x271f
+ field public static final int ERROR_NO_PROFILES_AVAILABLE = 10013; // 0x271d
+ field public static final int ERROR_OPERATION_BUSY = 10016; // 0x2720
+ field public static final int ERROR_SIM_MISSING = 10008; // 0x2718
+ field public static final int ERROR_TIME_OUT = 10005; // 0x2715
+ field public static final int ERROR_UNSUPPORTED_VERSION = 10007; // 0x2717
field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+ field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_ERROR_CODE";
+ field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_OPERATION_CODE";
+ field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE";
+ field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE";
field public static final String EXTRA_USE_QR_SCANNER = "android.telephony.euicc.extra.USE_QR_SCANNER";
field public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
+ field public static final int OPERATION_APDU = 8; // 0x8
+ field public static final int OPERATION_DOWNLOAD = 5; // 0x5
+ field public static final int OPERATION_EUICC_CARD = 3; // 0x3
+ field public static final int OPERATION_EUICC_GSMA = 7; // 0x7
+ field public static final int OPERATION_HTTP = 11; // 0xb
+ field public static final int OPERATION_METADATA = 6; // 0x6
+ field public static final int OPERATION_SIM_SLOT = 2; // 0x2
+ field public static final int OPERATION_SMDX = 9; // 0x9
+ field public static final int OPERATION_SMDX_SUBJECT_REASON_CODE = 10; // 0xa
+ field public static final int OPERATION_SWITCH = 4; // 0x4
+ field public static final int OPERATION_SYSTEM = 1; // 0x1
}
}
@@ -52548,6 +52642,7 @@ package android.view {
method public android.graphics.Canvas lockHardwareCanvas();
method public void readFromParcel(android.os.Parcel);
method public void release();
+ method public void setFrameRate(@FloatRange(from=0.0) float);
method @Deprecated public void unlockCanvas(android.graphics.Canvas);
method public void unlockCanvasAndPost(android.graphics.Canvas);
method public void writeToParcel(android.os.Parcel, int);
@@ -52591,6 +52686,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean);
@@ -52598,6 +52694,20 @@ package android.view {
field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl.Transaction> CREATOR;
}
+ public class SurfaceControlViewHost {
+ ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
+ method public void addView(@NonNull android.view.View, int, int);
+ method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
+ method public void relayout(int, int);
+ method public void release();
+ }
+
+ public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControlViewHost.SurfacePackage> CREATOR;
+ }
+
public interface SurfaceHolder {
method public void addCallback(android.view.SurfaceHolder.Callback);
method public android.view.Surface getSurface();
@@ -52642,7 +52752,9 @@ package android.view {
ctor public SurfaceView(android.content.Context, android.util.AttributeSet, int, int);
method public boolean gatherTransparentRegion(android.graphics.Region);
method public android.view.SurfaceHolder getHolder();
+ method @Nullable public android.os.IBinder getHostToken();
method public android.view.SurfaceControl getSurfaceControl();
+ method public void setChildSurfacePackage(@NonNull android.view.SurfaceControlViewHost.SurfacePackage);
method public void setSecure(boolean);
method public void setZOrderMediaOverlay(boolean);
method public void setZOrderOnTop(boolean);
@@ -52782,7 +52894,7 @@ package android.view {
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
method @CallSuper public void dispatchStartTemporaryDetach();
- method public void dispatchSystemUiVisibilityChanged(int);
+ method @Deprecated public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public boolean dispatchUnhandledMove(android.view.View, int);
@@ -52792,7 +52904,7 @@ package android.view {
method public void dispatchWindowInsetsAnimationPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets);
method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
- method public void dispatchWindowSystemUiVisiblityChanged(int);
+ method @Deprecated public void dispatchWindowSystemUiVisiblityChanged(int);
method public void dispatchWindowVisibilityChanged(int);
method @CallSuper public void draw(android.graphics.Canvas);
method @CallSuper public void drawableHotspotChanged(float, float);
@@ -52945,7 +53057,7 @@ package android.view {
method protected int getSuggestedMinimumHeight();
method protected int getSuggestedMinimumWidth();
method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects();
- method public int getSystemUiVisibility();
+ method @Deprecated public int getSystemUiVisibility();
method @android.view.ViewDebug.ExportedProperty public Object getTag();
method public Object getTag(int);
method @android.view.ViewDebug.ExportedProperty(category="text", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_INHERIT, to="INHERIT"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_GRAVITY, to="GRAVITY"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_TEXT_START, to="TEXT_START"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_TEXT_END, to="TEXT_END"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_CENTER, to="CENTER"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_VIEW_START, to="VIEW_START"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_VIEW_END, to="VIEW_END")}) public int getTextAlignment();
@@ -52973,7 +53085,7 @@ package android.view {
method protected int getWindowAttachCount();
method public android.view.WindowId getWindowId();
method @Nullable public android.view.WindowInsetsController getWindowInsetsController();
- method public int getWindowSystemUiVisibility();
+ method @Deprecated public int getWindowSystemUiVisibility();
method public android.os.IBinder getWindowToken();
method public int getWindowVisibility();
method public void getWindowVisibleDisplayFrame(android.graphics.Rect);
@@ -53111,7 +53223,7 @@ package android.view {
method @CallSuper public void onVisibilityAggregated(boolean);
method protected void onVisibilityChanged(@NonNull android.view.View, int);
method public void onWindowFocusChanged(boolean);
- method public void onWindowSystemUiVisibilityChanged(int);
+ method @Deprecated public void onWindowSystemUiVisibilityChanged(int);
method protected void onWindowVisibilityChanged(int);
method protected boolean overScrollBy(int, int, int, int, int, int, int, int, boolean);
method public boolean performAccessibilityAction(int, android.os.Bundle);
@@ -53253,7 +53365,7 @@ package android.view {
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
- method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
+ method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
method public void setOutlineAmbientShadowColor(@ColorInt int);
method public void setOutlineProvider(android.view.ViewOutlineProvider);
@@ -53290,7 +53402,7 @@ package android.view {
method public void setStateDescription(@Nullable CharSequence);
method public void setStateListAnimator(android.animation.StateListAnimator);
method public void setSystemGestureExclusionRects(@NonNull java.util.List<android.graphics.Rect>);
- method public void setSystemUiVisibility(int);
+ method @Deprecated public void setSystemUiVisibility(int);
method public void setTag(Object);
method public void setTag(int, Object);
method public void setTextAlignment(int);
@@ -53468,18 +53580,18 @@ package android.view {
field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
field @Deprecated public static final int STATUS_BAR_HIDDEN = 1; // 0x1
field @Deprecated public static final int STATUS_BAR_VISIBLE = 0; // 0x0
- field public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
- field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
- field public static final int SYSTEM_UI_FLAG_IMMERSIVE = 2048; // 0x800
- field public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096; // 0x1000
- field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
- field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
- field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
- field public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 16; // 0x10
- field public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
- field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
- field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
- field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
+ field @Deprecated public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
+ field @Deprecated public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
+ field @Deprecated public static final int SYSTEM_UI_FLAG_IMMERSIVE = 2048; // 0x800
+ field @Deprecated public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096; // 0x1000
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 16; // 0x10
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
+ field @Deprecated public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
+ field @Deprecated public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
+ field @Deprecated public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
field public static final int TEXT_ALIGNMENT_CENTER = 4; // 0x4
field public static final int TEXT_ALIGNMENT_GRAVITY = 1; // 0x1
field public static final int TEXT_ALIGNMENT_INHERIT = 0; // 0x0
@@ -53603,8 +53715,8 @@ package android.view {
method public void onScrollChange(android.view.View, int, int, int, int);
}
- public static interface View.OnSystemUiVisibilityChangeListener {
- method public void onSystemUiVisibilityChange(int);
+ @Deprecated public static interface View.OnSystemUiVisibilityChangeListener {
+ method @Deprecated public void onSystemUiVisibilityChange(int);
}
public static interface View.OnTouchListener {
@@ -54241,6 +54353,7 @@ package android.view {
method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
method public boolean requestFeature(int);
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
+ method public void resetOnContentApplyWindowInsetsListener();
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
method public void setAllowEnterTransitionOverlap(boolean);
@@ -54279,6 +54392,7 @@ package android.view {
method public abstract void setNavigationBarColor(@ColorInt int);
method public void setNavigationBarContrastEnforced(boolean);
method public void setNavigationBarDividerColor(@ColorInt int);
+ method public void setOnContentApplyWindowInsetsListener(@Nullable android.view.Window.OnContentApplyWindowInsetsListener);
method public void setPreferMinimalPostProcessing(boolean);
method public void setReenterTransition(android.transition.Transition);
method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
@@ -54373,6 +54487,10 @@ package android.view {
method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static interface Window.OnContentApplyWindowInsetsListener {
+ method @NonNull public android.util.Pair<android.graphics.Insets,android.view.WindowInsets> onContentApplyWindowInsets(@NonNull android.view.WindowInsets);
+ }
+
public static interface Window.OnFrameMetricsAvailableListener {
method public void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
}
@@ -54417,23 +54535,23 @@ package android.view {
method @Deprecated @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
method @Nullable public android.view.DisplayCutout getDisplayCutout();
method @NonNull public android.graphics.Insets getInsets(int);
- method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
- method @NonNull public android.graphics.Insets getMaxInsets(int) throws java.lang.IllegalArgumentException;
- method public int getStableInsetBottom();
- method public int getStableInsetLeft();
- method public int getStableInsetRight();
- method public int getStableInsetTop();
- method @NonNull public android.graphics.Insets getStableInsets();
- method @NonNull public android.graphics.Insets getSystemGestureInsets();
- method public int getSystemWindowInsetBottom();
- method public int getSystemWindowInsetLeft();
- method public int getSystemWindowInsetRight();
- method public int getSystemWindowInsetTop();
- method @NonNull public android.graphics.Insets getSystemWindowInsets();
- method @NonNull public android.graphics.Insets getTappableElementInsets();
+ method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
+ method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
+ method @Deprecated public int getStableInsetBottom();
+ method @Deprecated public int getStableInsetLeft();
+ method @Deprecated public int getStableInsetRight();
+ method @Deprecated public int getStableInsetTop();
+ method @Deprecated @NonNull public android.graphics.Insets getStableInsets();
+ method @Deprecated @NonNull public android.graphics.Insets getSystemGestureInsets();
+ method @Deprecated public int getSystemWindowInsetBottom();
+ method @Deprecated public int getSystemWindowInsetLeft();
+ method @Deprecated public int getSystemWindowInsetRight();
+ method @Deprecated public int getSystemWindowInsetTop();
+ method @Deprecated @NonNull public android.graphics.Insets getSystemWindowInsets();
+ method @Deprecated @NonNull public android.graphics.Insets getTappableElementInsets();
method public boolean hasInsets();
- method public boolean hasStableInsets();
- method public boolean hasSystemWindowInsets();
+ method @Deprecated public boolean hasStableInsets();
+ method @Deprecated public boolean hasSystemWindowInsets();
method @NonNull public android.view.WindowInsets inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
method public boolean isConsumed();
method public boolean isRound();
@@ -54449,17 +54567,24 @@ package android.view {
method @NonNull public android.view.WindowInsets build();
method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
- method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
- method @NonNull public android.view.WindowInsets.Builder setMaxInsets(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
- method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
- method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
- method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
- method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
+ method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
+ method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
+ method @Deprecated @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
+ method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
+ method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
+ method @Deprecated @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setVisible(int, boolean);
}
- public static final class WindowInsets.Type {
+ public static final class WindowInsets.Side {
method public static int all();
+ field public static final int BOTTOM = 8; // 0x8
+ field public static final int LEFT = 1; // 0x1
+ field public static final int RIGHT = 4; // 0x4
+ field public static final int TOP = 2; // 0x2
+ }
+
+ public static final class WindowInsets.Type {
method public static int captionBar();
method public static int ime();
method public static int mandatorySystemGestures();
@@ -54468,7 +54593,6 @@ package android.view {
method public static int systemBars();
method public static int systemGestures();
method public static int tappableElement();
- method public static int windowDecor();
}
public interface WindowInsetsAnimationCallback {
@@ -54496,7 +54620,7 @@ package android.view {
method public float getInterpolatedFraction();
method @Nullable public android.view.animation.Interpolator getInterpolator();
method public int getTypeMask();
- method public void setDuration(long);
+ method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
}
@@ -54517,19 +54641,27 @@ package android.view {
}
public interface WindowInsetsController {
- method public default void controlInputMethodAnimation(long, @NonNull android.view.WindowInsetsAnimationControlListener);
+ method public default void controlInputMethodAnimation(long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
+ method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
+ method public void hide(int);
method public default void hideInputMethod();
method public void setSystemBarsAppearance(int, int);
method public void setSystemBarsBehavior(int);
+ method public void show(int);
method public default void showInputMethod();
field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
+ field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+ field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+ field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
}
public interface WindowManager extends android.view.ViewManager {
- method public android.view.Display getDefaultDisplay();
+ method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
+ method @Deprecated public android.view.Display getDefaultDisplay();
+ method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public void removeViewImmediate(android.view.View);
}
@@ -54555,9 +54687,15 @@ package android.view {
method public String debug(String);
method public int describeContents();
method public int getColorMode();
+ method public int getFitInsetsSides();
+ method public int getFitInsetsTypes();
method public final CharSequence getTitle();
+ method public boolean isFitInsetsIgnoringVisibility();
method public static boolean mayUseInputMethod(int);
method public void setColorMode(int);
+ method public void setFitInsetsIgnoringVisibility(boolean);
+ method public void setFitInsetsSides(int);
+ method public void setFitInsetsTypes(int);
method public final void setTitle(CharSequence);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALPHA_CHANGED = 128; // 0x80
@@ -54578,13 +54716,13 @@ package android.view {
field @Deprecated public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
field @Deprecated public static final int FLAG_DITHER = 4096; // 0x1000
field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
- field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
- field public static final int FLAG_FULLSCREEN = 1024; // 0x400
+ field @Deprecated public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
+ field @Deprecated public static final int FLAG_FULLSCREEN = 1024; // 0x400
field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
- field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
- field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
+ field @Deprecated public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
+ field @Deprecated public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
field @Deprecated public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
@@ -54598,8 +54736,8 @@ package android.view {
field @Deprecated public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
field @Deprecated public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
- field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
- field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
+ field @Deprecated public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
+ field @Deprecated public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
field @Deprecated public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000
field public static final int FORMAT_CHANGED = 8; // 0x8
@@ -54625,7 +54763,7 @@ package android.view {
field public static final int SCREEN_ORIENTATION_CHANGED = 1024; // 0x400
field public static final int SOFT_INPUT_ADJUST_NOTHING = 48; // 0x30
field public static final int SOFT_INPUT_ADJUST_PAN = 32; // 0x20
- field public static final int SOFT_INPUT_ADJUST_RESIZE = 16; // 0x10
+ field @Deprecated public static final int SOFT_INPUT_ADJUST_RESIZE = 16; // 0x10
field public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0; // 0x0
field public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 256; // 0x100
field public static final int SOFT_INPUT_MASK_ADJUST = 240; // 0xf0
@@ -54682,7 +54820,7 @@ package android.view {
field public float screenBrightness;
field public int screenOrientation;
field public int softInputMode;
- field public int systemUiVisibility;
+ field @Deprecated public int systemUiVisibility;
field public android.os.IBinder token;
field @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION, to="BASE_APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION, to="APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING, to="APPLICATION_STARTING"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION, to="DRAWN_APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, to="APPLICATION_PANEL"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA, to="APPLICATION_MEDIA"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, to="APPLICATION_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=0x3ed, to="APPLICATION_ABOVE_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, to="APPLICATION_ATTACHED_DIALOG"), @android.view.ViewDebug.IntToString(from=0x3ec, to="APPLICATION_MEDIA_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR, to="STATUS_BAR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR, to="SEARCH_BAR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PHONE, to="PHONE"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, to="SYSTEM_ALERT"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_TOAST, to="TOAST"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, to="SYSTEM_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE, to="PRIORITY_PHONE"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG, to="SYSTEM_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, to="KEYGUARD_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, to="SYSTEM_ERROR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD, to="INPUT_METHOD"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, to="INPUT_METHOD_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_WALLPAPER, to="WALLPAPER"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, to="STATUS_BAR_PANEL"), @android.view.ViewDebug.IntToString(from=0x7df, to="SECURE_SYSTEM_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7e0, to="DRAG"), @android.view.ViewDebug.IntToString(from=0x7e1, to="STATUS_BAR_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=0x7e2, to="POINTER"), @android.view.ViewDebug.IntToString(from=0x7e3, to="NAVIGATION_BAR"), @android.view.ViewDebug.IntToString(from=0x7e4, to="VOLUME_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7e5, to="BOOT_PROGRESS"), @android.view.ViewDebug.IntToString(from=0x7e6, to="INPUT_CONSUMER"), @android.view.ViewDebug.IntToString(from=0x7e7, to="DREAM"), @android.view.ViewDebug.IntToString(from=0x7e8, to="NAVIGATION_BAR_PANEL"), @android.view.ViewDebug.IntToString(from=0x7ea, to="DISPLAY_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7eb, to="MAGNIFICATION_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7f5, to="PRESENTATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, to="PRIVATE_PRESENTATION"), @android.view.ViewDebug.IntToString(from=0x7ef, to="VOICE_INTERACTION"), @android.view.ViewDebug.IntToString(from=0x7f1, to="VOICE_INTERACTION_STARTING"), @android.view.ViewDebug.IntToString(from=0x7f2, to="DOCK_DIVIDER"), @android.view.ViewDebug.IntToString(from=0x7f3, to="QS_DIALOG"), @android.view.ViewDebug.IntToString(from=0x7f4, to="SCREENSHOT"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, to="APPLICATION_OVERLAY")}) public int type;
field public float verticalMargin;
@@ -54692,6 +54830,12 @@ package android.view {
field @android.view.ViewDebug.ExportedProperty public int y;
}
+ public final class WindowMetrics {
+ ctor public WindowMetrics(@NonNull android.util.Size, @NonNull android.view.WindowInsets);
+ method @NonNull public android.util.Size getSize();
+ method @NonNull public android.view.WindowInsets getWindowInsets();
+ }
+
}
package android.view.accessibility {
@@ -55789,7 +55933,12 @@ package android.view.inputmethod {
ctor public EditorInfo();
method public int describeContents();
method public void dump(android.util.Printer, String);
+ method @Nullable public CharSequence getInitialSelectedText(int);
+ method @Nullable public CharSequence getInitialTextAfterCursor(int, int);
+ method @Nullable public CharSequence getInitialTextBeforeCursor(int, int);
method public final void makeCompatible(int);
+ method public void setInitialSurroundingSubText(@NonNull CharSequence, int);
+ method public void setInitialSurroundingText(@NonNull CharSequence);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR;
field public static final int IME_ACTION_DONE = 6; // 0x6
@@ -55869,10 +56018,13 @@ package android.view.inputmethod {
method @Nullable public String[] getAutofillHints();
method @NonNull public android.view.inline.InlinePresentationSpec getPresentationSpec();
method @NonNull public String getSource();
+ method @NonNull public String getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionInfo> CREATOR;
field public static final String SOURCE_AUTOFILL = "android:autofill";
field public static final String SOURCE_PLATFORM = "android:platform";
+ field public static final String TYPE_ACTION = "android:autofill:action";
+ field public static final String TYPE_SUGGESTION = "android:autofill:suggestion";
}
public final class InlineSuggestionsRequest implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 2aac908b3937..9b2e19cfc620 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -55,13 +55,16 @@ package android {
field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
field public static final String CAPTURE_MEDIA_OUTPUT = "android.permission.CAPTURE_MEDIA_OUTPUT";
field public static final String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
+ field public static final String CAPTURE_VOICE_COMMUNICATION_OUTPUT = "android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+ field public static final String COMPANION_APPROVE_WIFI_CONNECTIONS = "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONFIGURE_WIFI_DISPLAY = "android.permission.CONFIGURE_WIFI_DISPLAY";
field @Deprecated public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+ field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
@@ -129,6 +132,7 @@ package android {
field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
+ field public static final String MONITOR_DEVICE_CONFIG_ACCESS = "android.permission.MONITOR_DEVICE_CONFIG_ACCESS";
field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
@@ -186,6 +190,7 @@ package android {
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS";
@@ -231,7 +236,7 @@ package android {
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
- field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
+ field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
}
@@ -249,6 +254,7 @@ package android {
public static final class R.attr {
field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
+ field public static final int isAutofillInlineSuggestionTheme = 16844310; // 0x1010616
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int minExtensionVersion = 16844306; // 0x1010612
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
@@ -393,6 +399,7 @@ package android.app {
field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
+ field public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
@@ -1718,7 +1725,7 @@ package android.bluetooth.le {
package android.companion {
public final class CompanionDeviceManager {
- method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociated(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
+ method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
}
}
@@ -2062,6 +2069,21 @@ package android.content.pm {
method @NonNull public final int getType();
}
+ public final class InstallationFile implements android.os.Parcelable {
+ ctor public InstallationFile(@NonNull String, long, @Nullable byte[]);
+ method public int describeContents();
+ method public int getFileType();
+ method @Nullable public byte[] getMetadata();
+ method @NonNull public String getName();
+ method public long getSize();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallationFile> CREATOR;
+ field public static final int FILE_TYPE_APK = 0; // 0x0
+ field public static final int FILE_TYPE_LIB = 1; // 0x1
+ field public static final int FILE_TYPE_OBB = 2; // 0x2
+ field public static final int FILE_TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
public final class InstantAppInfo implements android.os.Parcelable {
ctor public InstantAppInfo(android.content.pm.ApplicationInfo, String[], String[]);
ctor public InstantAppInfo(String, CharSequence, String[], String[]);
@@ -2152,11 +2174,16 @@ package android.content.pm {
field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
+ field public static final int LOCATION_DATA_APP = 0; // 0x0
+ field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
+ field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
}
public static class PackageInstaller.Session implements java.io.Closeable {
- method public void addFile(@NonNull String, long, @NonNull byte[]);
+ method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
+ method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
+ method public void removeFile(int, @NonNull String);
}
public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
@@ -2241,6 +2268,7 @@ package android.content.pm {
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
+ field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
field public static final int FLAG_PERMISSION_GRANTED_BY_ROLE = 32768; // 0x8000
@@ -2927,6 +2955,48 @@ package android.hardware.hdmi {
}
+package android.hardware.lights {
+
+ public final class Light implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getId();
+ method public int getOrdinal();
+ method public int getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
+ }
+
+ public final class LightState implements android.os.Parcelable {
+ ctor public LightState(@ColorInt int);
+ method public int describeContents();
+ method @ColorInt public int getColor();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
+ }
+
+ public final class LightsManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
+ method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
+ field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+ }
+
+ public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ }
+
+ public final class LightsRequest {
+ }
+
+ public static final class LightsRequest.Builder {
+ ctor public LightsRequest.Builder();
+ method @NonNull public android.hardware.lights.LightsRequest build();
+ method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
+ method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+ }
+
+}
+
package android.hardware.location {
public class ContextHubClient implements java.io.Closeable {
@@ -3639,9 +3709,34 @@ package android.hardware.radio {
package android.hardware.soundtrigger {
public class SoundTrigger {
+ field public static final int RECOGNITION_MODE_GENERIC = 8; // 0x8
+ field public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 4; // 0x4
+ field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
+ field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
field public static final int STATUS_OK = 0; // 0x0
}
+ public static final class SoundTrigger.Keyphrase implements android.os.Parcelable {
+ ctor public SoundTrigger.Keyphrase(int, int, @NonNull java.util.Locale, @NonNull String, @Nullable int[]);
+ method @NonNull public static android.hardware.soundtrigger.SoundTrigger.Keyphrase readFromParcel(@NonNull android.os.Parcel);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.Keyphrase> CREATOR;
+ field public final int id;
+ field @NonNull public final java.util.Locale locale;
+ field public final int recognitionModes;
+ field @NonNull public final String text;
+ field @NonNull public final int[] users;
+ }
+
+ public static final class SoundTrigger.KeyphraseSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable {
+ ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int);
+ ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[]);
+ method @NonNull public static android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel readFromParcel(@NonNull android.os.Parcel);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel> CREATOR;
+ field @NonNull public final android.hardware.soundtrigger.SoundTrigger.Keyphrase[] keyphrases;
+ }
+
public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
@@ -3680,6 +3775,16 @@ package android.hardware.soundtrigger {
method public boolean isCaptureAvailable();
}
+ public static class SoundTrigger.SoundModel {
+ field public static final int TYPE_GENERIC_SOUND = 1; // 0x1
+ field public static final int TYPE_KEYPHRASE = 0; // 0x0
+ field @NonNull public final byte[] data;
+ field public final int type;
+ field @NonNull public final java.util.UUID uuid;
+ field @NonNull public final java.util.UUID vendorUuid;
+ field public final int version;
+ }
+
}
package android.hardware.usb {
@@ -4189,9 +4294,11 @@ package android.media {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
method public void clearAudioServerStateCallback();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @IntRange(from=0) public int getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAddress> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
+ method @IntRange(from=0) public int getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
@@ -4205,6 +4312,7 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) int);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAddress);
@@ -4331,6 +4439,7 @@ package android.media.audiopolicy {
field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
field public static final int RULE_MATCH_UID = 4; // 0x4
+ field public static final int RULE_MATCH_USERID = 8; // 0x8
}
public static class AudioMixingRule.Builder {
@@ -4351,9 +4460,11 @@ package android.media.audiopolicy {
method public int getFocusDuckingBehavior();
method public int getStatus();
method public boolean removeUidDeviceAffinity(int);
+ method public boolean removeUserIdDeviceAffinity(int);
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setRegistration(String);
method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
+ method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
method public String toLogFriendlyString();
field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
@@ -5017,6 +5128,7 @@ package android.media.tv.tuner.filter {
}
public class MediaEvent extends android.media.tv.tuner.filter.FilterEvent {
+ method public long getAudioHandle();
method public long getAvDataId();
method public long getDataLength();
method @Nullable public android.media.tv.tuner.filter.AudioDescriptor getExtraMetaData();
@@ -5884,6 +5996,16 @@ package android.media.tv.tuner.frontend {
}
+package android.media.voice {
+
+ public final class KeyphraseModelManager {
+ method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void deleteKeyphraseSoundModel(int, @NonNull java.util.Locale);
+ method @Nullable @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int, @NonNull java.util.Locale);
+ method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void updateKeyphraseSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel);
+ }
+
+}
+
package android.metrics {
public class LogMaker {
@@ -5970,44 +6092,44 @@ package android.net {
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
field public static final int TETHERING_USB = 1; // 0x1
field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+ field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
field public static final int TYPE_NONE = -1; // 0xffffffff
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
- public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor public ConnectivityManager.OnStartTetheringCallback();
- method public void onTetheringFailed();
- method public void onTetheringStarted();
+ @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+ ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+ method @Deprecated public void onTetheringFailed();
+ method @Deprecated public void onTetheringStarted();
}
- public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
+ @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+ method @Deprecated public void onTetheringEntitlementResult(int);
}
- public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor public ConnectivityManager.OnTetheringEventCallback();
- method public void onUpstreamChanged(@Nullable android.net.Network);
+ @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+ ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+ method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
}
public class InvalidPacketException extends java.lang.Exception {
@@ -6079,13 +6201,18 @@ package android.net {
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
method public boolean isGlobalPreferred();
method public boolean isIpv4();
method public boolean isIpv6();
method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+ field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
}
public final class LinkProperties implements android.os.Parcelable {
@@ -6213,7 +6340,7 @@ package android.net {
public class NetworkKey implements android.os.Parcelable {
ctor public NetworkKey(android.net.WifiKey);
- method @Nullable public static android.net.NetworkKey createFromScanResult(@Nullable android.net.wifi.ScanResult);
+ method @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
@@ -6264,12 +6391,12 @@ package android.net {
}
public class NetworkScoreManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage();
- method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
- method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public boolean requestScores(@NonNull android.net.NetworkKey[]) throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public String getActiveScorerPackage();
+ method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
+ method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public boolean requestScores(@NonNull java.util.Collection<android.net.NetworkKey>) throws java.lang.SecurityException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
@@ -6284,9 +6411,10 @@ package android.net {
field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
}
- public static interface NetworkScoreManager.NetworkScoreCallback {
- method public void clearScores();
- method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>);
+ public abstract static class NetworkScoreManager.NetworkScoreCallback {
+ ctor public NetworkScoreManager.NetworkScoreCallback();
+ method public abstract void onScoresInvalidated();
+ method public abstract void onScoresUpdated(@NonNull java.util.Collection<android.net.ScoredNetwork>);
}
public abstract class NetworkSpecifier {
@@ -6395,17 +6523,82 @@ package android.net {
method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
}
- public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public StringNetworkSpecifier(@NonNull String);
- method public int describeContents();
+ public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
method public boolean satisfiedBy(android.net.NetworkSpecifier);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StringNetworkSpecifier> CREATOR;
- field @NonNull public final String specifier;
}
- public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- method public boolean satisfiedBy(android.net.NetworkSpecifier);
+ public class TetheringManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+ field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+ field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+ field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_INVALID = -1; // 0xffffffff
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+ field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+ field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+ field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+ field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+ field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+ field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+ field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+ field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+ field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+ field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+ field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+ field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ }
+
+ public static interface TetheringManager.OnTetheringEntitlementResultListener {
+ method public void onTetheringEntitlementResult(int);
+ }
+
+ public abstract static class TetheringManager.StartTetheringCallback {
+ ctor public TetheringManager.StartTetheringCallback();
+ method public void onTetheringFailed(int);
+ method public void onTetheringStarted();
+ }
+
+ public abstract static class TetheringManager.TetheringEventCallback {
+ ctor public TetheringManager.TetheringEventCallback();
+ method public void onError(@NonNull String, int);
+ method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+ method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheringSupported(boolean);
+ method public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+ ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+ }
+
+ public static class TetheringManager.TetheringRequest {
+ }
+
+ public static class TetheringManager.TetheringRequest.Builder {
+ ctor public TetheringManager.TetheringRequest.Builder(int);
+ method @NonNull public android.net.TetheringManager.TetheringRequest build();
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
}
public class TrafficStats {
@@ -7365,12 +7558,12 @@ package android.net.wifi {
method @NonNull public String getCaPath();
method @NonNull public String getClientCertificateAlias();
method public int getOcsp();
- method @Nullable public String getWapiCertSuite();
+ method @NonNull public String getWapiCertSuite();
method public void setCaCertificateAliases(@Nullable String[]);
- method public void setCaPath(@Nullable String);
- method public void setClientCertificateAlias(@Nullable String);
+ method public void setCaPath(@NonNull String);
+ method public void setClientCertificateAlias(@NonNull String);
method public void setOcsp(int);
- method public void setWapiCertSuite(@Nullable String);
+ method public void setWapiCertSuite(@NonNull String);
field public static final int OCSP_NONE = 0; // 0x0
field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1
field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3
@@ -7408,6 +7601,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 allowAutojoinGlobal(boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void clearWifiConnectedNetworkScorer();
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);
@@ -7438,11 +7632,8 @@ package android.net.wifi {
method public boolean isPortableHotspotSupported();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
@@ -7453,6 +7644,7 @@ package android.net.wifi {
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
@@ -7818,6 +8010,7 @@ package android.net.wifi.hotspot2 {
}
public final class PasspointConfiguration implements android.os.Parcelable {
+ method public int getMeteredOverride();
method public boolean isAutoJoinEnabled();
method public boolean isMacRandomizationEnabled();
}
@@ -8178,22 +8371,22 @@ package android.os {
method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int);
}
- public class BatteryStatsManager {
+ public final class BatteryStatsManager {
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats();
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiMulticastDisabled(int);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiMulticastEnabled(int);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiOff();
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiOn();
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStartedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiState(int, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiSupplicantStateChanged(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(int);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(int);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiState(int, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiSupplicantStateChanged(int, boolean);
field public static final int WIFI_STATE_OFF = 0; // 0x0
field public static final int WIFI_STATE_OFF_SCANNING = 1; // 0x1
field public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; // 0x5
@@ -8603,6 +8796,26 @@ package android.os {
field public static final int TUPLE_VALUE_TYPE = 7; // 0x7
}
+ public class StatsFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
+ }
+
+ public class StatsServiceManager {
+ method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
+ method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
+ method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsdServiceRegisterer();
+ }
+
+ public static class StatsServiceManager.ServiceNotFoundException extends java.lang.Exception {
+ ctor public StatsServiceManager.ServiceNotFoundException(@NonNull String);
+ }
+
+ public static final class StatsServiceManager.ServiceRegisterer {
+ method @Nullable public android.os.IBinder get();
+ method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
+ }
+
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
@@ -8637,16 +8850,13 @@ package android.os {
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();
}
@@ -8867,12 +9077,12 @@ package android.os.connectivity {
public final class WifiBatteryStats implements android.os.Parcelable {
method public int describeContents();
+ method public long getAppScanRequestCount();
method public long getEnergyConsumedMaMillis();
method public long getIdleTimeMillis();
method public long getKernelActiveTimeMillis();
method public long getLoggingDurationMillis();
method public long getMonitoredRailChargeConsumedMaMillis();
- method public long getNumAppScanRequest();
method public long getNumBytesRx();
method public long getNumBytesTx();
method public long getNumPacketsRx();
@@ -9571,6 +9781,7 @@ package android.provider {
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 IMS_RCS_UCE_ENABLED = "ims_rcs_uce_enabled";
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";
@@ -9983,6 +10194,16 @@ package android.service.dataloader {
public abstract class DataLoaderService extends android.app.Service {
ctor public DataLoaderService();
+ method @Nullable public android.service.dataloader.DataLoaderService.DataLoader onCreateDataLoader();
+ }
+
+ public static interface DataLoaderService.DataLoader {
+ method public boolean onCreate(@NonNull android.content.pm.DataLoaderParams, @NonNull android.service.dataloader.DataLoaderService.FileSystemConnector);
+ method public boolean onPrepareImage(@NonNull java.util.Collection<android.content.pm.InstallationFile>, @NonNull java.util.Collection<java.lang.String>);
+ }
+
+ public static final class DataLoaderService.FileSystemConnector {
+ method public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
}
}
@@ -10051,6 +10272,7 @@ package android.service.euicc {
public abstract class EuiccService extends android.app.Service {
ctor public EuiccService();
method public void dump(@NonNull java.io.PrintWriter);
+ method public int encodeSmdxSubjectAndReasonCode(@Nullable String, @Nullable String) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException, java.lang.UnsupportedOperationException;
method @CallSuper public android.os.IBinder onBind(android.content.Intent);
method public abstract int onDeleteSubscription(int, String);
method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
@@ -10411,6 +10633,14 @@ package android.service.trust {
}
+package android.service.voice {
+
+ public class VoiceInteractionService extends android.app.Service {
+ method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
+ }
+
+}
+
package android.service.wallpaper {
public class WallpaperService.Engine {
@@ -11399,7 +11629,7 @@ package android.telephony {
}
public final class ModemActivityInfo implements android.os.Parcelable {
- ctor public ModemActivityInfo(long, int, int, @Nullable int[], int);
+ ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
method public int describeContents();
method public int getIdleTimeMillis();
method public int getReceiveTimeMillis();
@@ -11971,7 +12201,6 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isManualNetworkSelectionAllowed();
method public boolean isModemEnabledForSlot(int);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
@@ -12139,6 +12368,7 @@ package android.telephony {
public class TelephonyRegistryManager {
method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
+ method public void listenForSubscriber(int, @NonNull String, @NonNull String, @NonNull android.telephony.PhoneStateListener, int, boolean);
method public void notifyActiveDataSubIdChanged(int);
method public void notifyBarringInfoChanged(int, int, @NonNull android.telephony.BarringInfo);
method public void notifyCallForwardingChanged(int, boolean);
@@ -12155,6 +12385,9 @@ package android.telephony {
method public void notifyEmergencyNumberList(int, int);
method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo);
method public void notifyMessageWaitingChanged(int, int, boolean);
+ method public void notifyOpportunisticSubscriptionInfoChanged();
+ method public void notifyOutgoingEmergencyCall(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
+ method public void notifyOutgoingEmergencySms(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
method public void notifyPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
method public void notifyPreciseCallState(int, int, int, int, int);
method public void notifyPreciseDataConnectionFailed(int, int, int, @Nullable String, int);
@@ -12163,6 +12396,7 @@ package android.telephony {
method public void notifyServiceStateChanged(int, int, @NonNull android.telephony.ServiceState);
method public void notifySignalStrengthChanged(int, int, @NonNull android.telephony.SignalStrength);
method public void notifySrvccStateChanged(int, int);
+ method public void notifySubscriptionInfoChanged();
method public void notifyUserMobileDataStateChanged(int, int, boolean);
method public void notifyVoiceActivationStateChanged(int, int, int);
method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
@@ -12468,6 +12702,11 @@ package android.telephony.euicc {
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getSupportedCountries();
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getUnsupportedCountries();
+ method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public boolean isSupportedCountry(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setSupportedCountries(@NonNull java.util.List<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setUnsupportedCountries(@NonNull java.util.List<java.lang.String>);
field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
field @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
@@ -12633,6 +12872,7 @@ package android.telephony.ims {
field public static final String EXTRA_DIALSTRING = "dialstring";
field public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
field public static final String EXTRA_EMERGENCY_CALL = "e_call";
+ field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
field public static final String EXTRA_IS_CALL_PULL = "CallPull";
field public static final String EXTRA_OI = "oi";
field public static final String EXTRA_OIR = "oir";
@@ -13161,6 +13401,29 @@ package android.telephony.ims {
method @NonNull public android.telephony.ims.RcsContactUceCapability build();
}
+ public class RcsUceAdapter {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+ field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+ field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+ field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+ field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+ field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
+ }
+
}
package android.telephony.ims.feature {
@@ -13422,6 +13685,7 @@ package android.telephony.ims.stub {
method public int transact(android.os.Bundle);
method public int updateCallBarring(int, int, String[]);
method public int updateCallBarringForServiceClass(int, int, String[], int);
+ method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
method public int updateCallForward(int, int, String, int, int);
method public int updateCallWaiting(boolean, int);
method public int updateClip(boolean);
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index cf1a34a5934b..2f1889cea4eb 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -8,6 +8,15 @@ ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
ActionValue: android.net.wifi.WifiManager#ACTION_LINK_CONFIGURATION_CHANGED:
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+ Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
ArrayReturn: android.bluetooth.BluetoothCodecStatus#BluetoothCodecStatus(android.bluetooth.BluetoothCodecConfig, android.bluetooth.BluetoothCodecConfig[], android.bluetooth.BluetoothCodecConfig[]) parameter #1:
Method parameter should be Collection<BluetoothCodecConfig> (or subclass) instead of raw array; was `android.bluetooth.BluetoothCodecConfig[]`
diff --git a/api/test-current.txt b/api/test-current.txt
index dc6b5154e62d..259d401c2ada 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10,6 +10,7 @@ package android {
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+ field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
@@ -19,7 +20,7 @@ package android {
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
- field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
+ field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
}
@@ -704,7 +705,7 @@ package android.bluetooth {
package android.companion {
public final class CompanionDeviceManager {
- method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociated(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
+ method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
}
}
@@ -758,7 +759,6 @@ package android.content {
method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public java.io.File getCrateDir(@NonNull String);
- method public abstract android.view.Display getDisplay();
method public abstract int getDisplayId();
method public android.os.UserHandle getUser();
method public int getUserId();
@@ -779,7 +779,6 @@ package android.content {
}
public class ContextWrapper extends android.content.Context {
- method public android.view.Display getDisplay();
method public int getDisplayId();
}
@@ -1132,6 +1131,49 @@ package android.hardware.display {
}
+package android.hardware.lights {
+
+ public final class Light implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getId();
+ method public int getOrdinal();
+ method public int getType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
+ }
+
+ public final class LightState implements android.os.Parcelable {
+ ctor public LightState(@ColorInt int);
+ method public int describeContents();
+ method @ColorInt public int getColor();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
+ }
+
+ public final class LightsManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightState getLightState(@NonNull android.hardware.lights.Light);
+ method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
+ method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
+ field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+ }
+
+ public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ }
+
+ public final class LightsRequest {
+ }
+
+ public static final class LightsRequest.Builder {
+ ctor public LightsRequest.Builder();
+ method @NonNull public android.hardware.lights.LightsRequest build();
+ method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
+ method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+ }
+
+}
+
package android.location {
public final class GnssClock implements android.os.Parcelable {
@@ -1145,6 +1187,9 @@ package android.location {
method public void resetElapsedRealtimeUncertaintyNanos();
method public void resetFullBiasNanos();
method public void resetLeapSecond();
+ method public void resetReferenceCarrierFrequencyHzForIsb();
+ method public void resetReferenceCodeTypeForIsb();
+ method public void resetReferenceConstellationTypeForIsb();
method public void resetTimeUncertaintyNanos();
method public void set(android.location.GnssClock);
method public void setBiasNanos(double);
@@ -1156,6 +1201,9 @@ package android.location {
method public void setFullBiasNanos(long);
method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(int);
+ method public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from=0.0) double);
+ method public void setReferenceCodeTypeForIsb(@NonNull String);
+ method public void setReferenceConstellationTypeForIsb(int);
method public void setTimeNanos(long);
method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
}
@@ -1170,6 +1218,10 @@ package android.location {
method @Deprecated public void resetCarrierPhase();
method @Deprecated public void resetCarrierPhaseUncertainty();
method public void resetCodeType();
+ method public void resetReceiverInterSignalBiasNanos();
+ method public void resetReceiverInterSignalBiasUncertaintyNanos();
+ method public void resetSatelliteInterSignalBiasNanos();
+ method public void resetSatelliteInterSignalBiasUncertaintyNanos();
method public void resetSnrInDb();
method public void set(android.location.GnssMeasurement);
method public void setAccumulatedDeltaRangeMeters(double);
@@ -1189,6 +1241,10 @@ package android.location {
method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
method public void setReceivedSvTimeNanos(long);
method public void setReceivedSvTimeUncertaintyNanos(long);
+ method public void setReceiverInterSignalBiasNanos(double);
+ method public void setReceiverInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
+ method public void setSatelliteInterSignalBiasNanos(double);
+ method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
method public void setSnrInDb(double);
method public void setState(int);
method public void setSvid(int);
@@ -1399,6 +1455,7 @@ package android.media.audiopolicy {
field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
field public static final int RULE_MATCH_UID = 4; // 0x4
+ field public static final int RULE_MATCH_USERID = 8; // 0x8
}
public static class AudioMixingRule.Builder {
@@ -1419,9 +1476,11 @@ package android.media.audiopolicy {
method public int getFocusDuckingBehavior();
method public int getStatus();
method public boolean removeUidDeviceAffinity(int);
+ method public boolean removeUserIdDeviceAffinity(int);
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setRegistration(String);
method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
+ method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
method public String toLogFriendlyString();
field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
@@ -1562,9 +1621,12 @@ package android.net {
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
method public boolean isGlobalPreferred();
method public boolean isIpv4();
method public boolean isIpv6();
@@ -1664,6 +1726,80 @@ package android.net {
method public void teardownTestNetwork(@NonNull android.net.Network);
}
+ public class TetheringManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+ field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+ field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+ field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_INVALID = -1; // 0xffffffff
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+ field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+ field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+ field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+ field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+ field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+ field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+ field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+ field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+ field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+ field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+ field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+ field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ }
+
+ public static interface TetheringManager.OnTetheringEntitlementResultListener {
+ method public void onTetheringEntitlementResult(int);
+ }
+
+ public abstract static class TetheringManager.StartTetheringCallback {
+ ctor public TetheringManager.StartTetheringCallback();
+ method public void onTetheringFailed(int);
+ method public void onTetheringStarted();
+ }
+
+ public abstract static class TetheringManager.TetheringEventCallback {
+ ctor public TetheringManager.TetheringEventCallback();
+ method public void onError(@NonNull String, int);
+ method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+ method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheringSupported(boolean);
+ method public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+ ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+ }
+
+ public static class TetheringManager.TetheringRequest {
+ }
+
+ public static class TetheringManager.TetheringRequest.Builder {
+ ctor public TetheringManager.TetheringRequest.Builder(int);
+ method @NonNull public android.net.TetheringManager.TetheringRequest build();
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+ }
+
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -3383,6 +3519,7 @@ package android.telephony {
public class TelephonyRegistryManager {
method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor);
+ method public void listenForSubscriber(int, @NonNull String, @NonNull String, @NonNull android.telephony.PhoneStateListener, int, boolean);
method public void notifyActiveDataSubIdChanged(int);
method public void notifyBarringInfoChanged(int, int, @NonNull android.telephony.BarringInfo);
method public void notifyCallForwardingChanged(int, boolean);
@@ -3399,6 +3536,8 @@ package android.telephony {
method public void notifyEmergencyNumberList(int, int);
method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo);
method public void notifyMessageWaitingChanged(int, int, boolean);
+ method public void notifyOutgoingEmergencyCall(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
+ method public void notifyOutgoingEmergencySms(int, int, @NonNull android.telephony.emergency.EmergencyNumber);
method public void notifyPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
method public void notifyPreciseCallState(int, int, int, int, int);
method public void notifyPreciseDataConnectionFailed(int, int, int, @Nullable String, int);
@@ -3522,6 +3661,7 @@ package android.telephony.ims {
field public static final String EXTRA_DIALSTRING = "dialstring";
field public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
field public static final String EXTRA_EMERGENCY_CALL = "e_call";
+ field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
field public static final String EXTRA_IS_CALL_PULL = "CallPull";
field public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS";
field public static final String EXTRA_OI = "oi";
@@ -3999,6 +4139,29 @@ package android.telephony.ims {
method public void onProvisioningStringChanged(int, @NonNull String);
}
+ public class RcsUceAdapter {
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+ field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+ field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+ field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+ field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+ field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
+ }
+
}
package android.telephony.ims.feature {
@@ -4260,6 +4423,7 @@ package android.telephony.ims.stub {
method public int transact(android.os.Bundle);
method public int updateCallBarring(int, int, String[]);
method public int updateCallBarringForServiceClass(int, int, String[], int);
+ method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
method public int updateCallForward(int, int, String, int, int);
method public int updateCallWaiting(boolean, int);
method public int updateClip(boolean);
@@ -4547,22 +4711,6 @@ package android.view {
method public abstract String asyncImpl() default "";
}
- public class SurfaceControlViewHost {
- ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
- method public void addView(android.view.View, android.view.WindowManager.LayoutParams);
- method public void dispose();
- method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
- method public void relayout(android.view.WindowManager.LayoutParams);
- }
-
- public class SurfaceControlViewHost.SurfacePackage {
- method @NonNull public android.view.SurfaceControl getSurfaceControl();
- }
-
- public class SurfaceView extends android.view.View {
- method @Nullable public android.os.IBinder getInputToken();
- }
-
@UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
method public android.view.View getTooltipView();
method public boolean isAutofilled();
@@ -4607,7 +4755,7 @@ package android.view {
field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
field public CharSequence accessibilityTitle;
- field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC"), @android.view.ViewDebug.FlagToString(mask=0x4000000, equals=0x4000000, name="APPEARANCE_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x8000000, equals=0x8000000, name="BEHAVIOR_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x10000000, equals=0x10000000, name="FIT_INSETS_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x20000000, equals=0x20000000, name="ONLY_DRAW_BOTTOM_BAR_BACKGROUND")}) public int privateFlags;
+ field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC"), @android.view.ViewDebug.FlagToString(mask=0x4000000, equals=0x4000000, name="APPEARANCE_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x8000000, equals=0x8000000, name="BEHAVIOR_CONTROLLED"), @android.view.ViewDebug.FlagToString(mask=0x10000000, equals=0x10000000, name="FIT_INSETS_CONTROLLED")}) public int privateFlags;
}
}
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 603f7a259462..a9c18363d8b0 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -7,6 +7,16 @@ AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean):
ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+ Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
@@ -396,7 +406,13 @@ GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos
GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
-
+
+GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
+
+GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
+
+GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
+
GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
@@ -404,7 +420,15 @@ GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-
+
+GetterSetterNames: android.location.GnssMeasurement#setReceiverInterSignalBiasNanos(double):
+
+GetterSetterNames: android.location.GnssMeasurement#setReceiverInterSignalBiasUncertaintyNanos(double):
+
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
+
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
+
GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d05ac189c834..d9b3a6c05c2a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1724,6 +1724,7 @@ message WatchdogRollbackOccurred {
REASON_EXPLICIT_HEALTH_CHECK = 2;
REASON_APP_CRASH = 3;
REASON_APP_NOT_RESPONDING = 4;
+ REASON_NATIVE_CRASH_DURING_BOOT = 5;
}
optional RollbackReasonType rollback_reason = 4;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b82a67556fc0..48f0087f6b30 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -111,6 +111,8 @@ import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StatsFrameworkInitializer;
+import android.os.StatsServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -7326,6 +7328,15 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ float getFloatCoreSetting(String key, float defaultValue) {
+ synchronized (mResourcesManager) {
+ if (mCoreSettings != null) {
+ return mCoreSettings.getFloat(key, defaultValue);
+ }
+ return defaultValue;
+ }
+ }
+
private static class AndroidOs extends ForwardingOs {
/**
* Install selective syscall interception. For example, this is used to
@@ -7514,6 +7525,7 @@ public final class ActivityThread extends ClientTransactionHandler {
*/
public static void initializeMainlineModules() {
TelephonyFrameworkInitializer.setTelephonyServiceManager(new TelephonyServiceManager());
+ StatsFrameworkInitializer.setStatsServiceManager(new StatsServiceManager());
}
private void purgePendingResources() {
diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java
index 81e1565ee86c..f66bf0d89c37 100644
--- a/core/java/android/app/AppGlobals.java
+++ b/core/java/android/app/AppGlobals.java
@@ -75,4 +75,20 @@ public class AppGlobals {
return defaultValue;
}
}
+
+ /**
+ * Gets the value of a float core setting.
+ *
+ * @param key The setting key.
+ * @param defaultValue The setting default value.
+ * @return The core settings.
+ */
+ public static float getFloatCoreSetting(String key, float defaultValue) {
+ ActivityThread currentActivityThread = ActivityThread.currentActivityThread();
+ if (currentActivityThread != null) {
+ return currentActivityThread.getFloatCoreSetting(key, defaultValue);
+ } else {
+ return defaultValue;
+ }
+ }
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bc7e1e591021..46f86690a753 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1159,6 +1159,7 @@ public class AppOpsManager {
@SystemApi
public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
/** @hide Read device identifiers */
+ @SystemApi
public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
/** @hide Query all packages on device */
public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cd84310356b1..b7555ee1c04e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -19,7 +19,6 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -201,7 +200,7 @@ class ContextImpl extends Context {
@UnsupportedAppUsage
private @Nullable ClassLoader mClassLoader;
- private final @Nullable IBinder mActivityToken;
+ private final @Nullable IBinder mToken;
private final @NonNull UserHandle mUser;
@@ -219,7 +218,7 @@ class ContextImpl extends Context {
private final @NonNull ResourcesManager mResourcesManager;
@UnsupportedAppUsage
private @NonNull Resources mResources;
- private @Nullable Display mDisplay; // may be null if default display
+ private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mFlags;
@@ -244,6 +243,9 @@ class ContextImpl extends Context {
private final Object mSync = new Object();
+ private boolean mIsSystemOrSystemUiContext;
+ private boolean mIsUiContext;
+
@GuardedBy("mSync")
private File mDatabasesDir;
@GuardedBy("mSync")
@@ -1883,6 +1885,9 @@ class ContextImpl extends Context {
@Override
public Object getSystemService(String name) {
+ if (isUiComponent(name) && !isUiContext()) {
+ Log.w(TAG, name + " should be accessed from Activity or other visual Context");
+ }
return SystemServiceRegistry.getSystemService(this, name);
}
@@ -1891,6 +1896,15 @@ class ContextImpl extends Context {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
}
+ boolean isUiContext() {
+ return mIsSystemOrSystemUiContext || mIsUiContext;
+ }
+
+ private static boolean isUiComponent(String name) {
+ return WINDOW_SERVICE.equals(name) || LAYOUT_INFLATER_SERVICE.equals(name)
+ || WALLPAPER_SERVICE.equals(name);
+ }
+
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
@@ -2229,12 +2243,12 @@ class ContextImpl extends Context {
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
- ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mActivityToken,
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mToken,
new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
final int displayId = getDisplayId();
- c.setResources(createResources(mActivityToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, displayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
@@ -2258,18 +2272,18 @@ class ContextImpl extends Context {
// The system resources are loaded in every application, so we can safely copy
// the context without reloading Resources.
return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, null,
- mActivityToken, user, flags, null, null);
+ mToken, user, flags, null, null);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mFeatureId, null,
- mActivityToken, user, flags, null, null);
+ mToken, user, flags, null, null);
final int displayId = getDisplayId();
- c.setResources(createResources(mActivityToken, pi, null, displayId, null,
+ c.setResources(createResources(mToken, pi, null, displayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
@@ -2301,12 +2315,12 @@ class ContextImpl extends Context {
final String[] paths = mPackageInfo.getSplitPaths(splitName);
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
- mFeatureId, splitName, mActivityToken, mUser, mFlags, classLoader, null);
+ mFeatureId, splitName, mToken, mUser, mFlags, classLoader, null);
final int displayId = getDisplayId();
context.setResources(ResourcesManager.getInstance().getResources(
- mActivityToken,
+ mToken,
mPackageInfo.getResDir(),
paths,
mPackageInfo.getOverlayDirs(),
@@ -2325,10 +2339,10 @@ class ContextImpl extends Context {
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
- mSplitName, mActivityToken, mUser, mFlags, mClassLoader, null);
+ mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = getDisplayId();
- context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
+ context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
return context;
}
@@ -2340,19 +2354,36 @@ class ContextImpl extends Context {
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
- mSplitName, mActivityToken, mUser, mFlags, mClassLoader, null);
+ mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = display.getDisplayId();
- context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
+ context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
null, getDisplayAdjustments(displayId).getCompatibilityInfo()));
context.mDisplay = display;
return context;
}
@Override
+ public @NonNull WindowContext createWindowContext(int type) {
+ if (getDisplay() == null) {
+ throw new UnsupportedOperationException("WindowContext can only be created from "
+ + "other visual contexts, such as Activity or one created with "
+ + "Context#createDisplayContext(Display)");
+ }
+ return new WindowContext(this, null /* token */, type);
+ }
+
+ ContextImpl createBaseWindowContext(IBinder token) {
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+ mSplitName, token, mUser, mFlags, mClassLoader, null);
+ context.mIsUiContext = true;
+ return context;
+ }
+
+ @Override
public @NonNull Context createFeatureContext(@Nullable String featureId) {
return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName,
- mActivityToken, mUser, mFlags, mClassLoader, null);
+ mToken, mUser, mFlags, mClassLoader, null);
}
@Override
@@ -2360,7 +2391,7 @@ class ContextImpl extends Context {
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
| Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
- mActivityToken, mUser, flags, mClassLoader, null);
+ mToken, mUser, flags, mClassLoader, null);
}
@Override
@@ -2368,7 +2399,7 @@ class ContextImpl extends Context {
final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
| Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
- mActivityToken, mUser, flags, mClassLoader, null);
+ mToken, mUser, flags, mClassLoader, null);
}
@Override
@@ -2394,8 +2425,6 @@ class ContextImpl extends Context {
return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
}
- @UnsupportedAppUsage
- @TestApi
@Override
public Display getDisplay() {
if (mDisplay == null) {
@@ -2408,7 +2437,8 @@ class ContextImpl extends Context {
@Override
public int getDisplayId() {
- return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ final Display display = getDisplay();
+ return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
}
@Override
@@ -2518,6 +2548,7 @@ class ContextImpl extends Context {
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
+ context.mIsSystemOrSystemUiContext = true;
return context;
}
@@ -2535,6 +2566,7 @@ class ContextImpl extends Context {
context.setResources(createResources(null, packageInfo, null, displayId, null,
packageInfo.getCompatibilityInfo()));
context.updateDisplay(displayId);
+ context.mIsSystemOrSystemUiContext = true;
return context;
}
@@ -2584,6 +2616,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
activityInfo.splitName, activityToken, null, 0, classLoader, null);
+ context.mIsUiContext = true;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -2629,7 +2662,7 @@ class ContextImpl extends Context {
}
mMainThread = mainThread;
- mActivityToken = activityToken;
+ mToken = activityToken;
mFlags = flags;
if (user == null) {
@@ -2649,6 +2682,7 @@ class ContextImpl extends Context {
opPackageName = container.mOpPackageName;
setResources(container.mResources);
mDisplay = container.mDisplay;
+ mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
@@ -2710,7 +2744,7 @@ class ContextImpl extends Context {
@Override
@UnsupportedAppUsage
public IBinder getActivityToken() {
- return mActivityToken;
+ return mToken;
}
private void checkMode(int mode) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c1e535643ddf..dcd179f8694d 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -89,6 +89,7 @@ import android.hardware.hdmi.IHdmiControlService;
import android.hardware.input.InputManager;
import android.hardware.iris.IIrisService;
import android.hardware.iris.IrisManager;
+import android.hardware.lights.LightsManager;
import android.hardware.location.ContextHubManager;
import android.hardware.radio.RadioManager;
import android.hardware.usb.IUsbManager;
@@ -106,6 +107,7 @@ import android.media.session.MediaSessionManager;
import android.media.soundtrigger.SoundTriggerManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityThread;
import android.net.EthernetManager;
@@ -148,6 +150,7 @@ import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.StatsFrameworkInitializer;
import android.os.SystemConfigManager;
import android.os.SystemUpdateManager;
import android.os.SystemVibrator;
@@ -376,6 +379,18 @@ public final class SystemServiceRegistry {
return new IpSecManager(ctx, service);
}});
+ registerService(Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+ ConnectivityDiagnosticsManager.class,
+ new CachedServiceFetcher<ConnectivityDiagnosticsManager>() {
+ @Override
+ public ConnectivityDiagnosticsManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ // ConnectivityDiagnosticsManager is backed by ConnectivityService
+ IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ return new ConnectivityDiagnosticsManager(ctx, service);
+ }});
+
registerService(
Context.TEST_NETWORK_SERVICE,
TestNetworkManager.class,
@@ -587,13 +602,6 @@ public final class SystemServiceRegistry {
return SensorPrivacyManager.getInstance(ctx);
}});
- registerService(Context.STATS_MANAGER, StatsManager.class,
- new CachedServiceFetcher<StatsManager>() {
- @Override
- public StatsManager createService(ContextImpl ctx) {
- return new StatsManager(ctx.getOuterContext());
- }});
-
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
@Override
@@ -1262,6 +1270,13 @@ public final class SystemServiceRegistry {
Context.DATA_LOADER_MANAGER_SERVICE);
return new DataLoaderManager(IDataLoaderManager.Stub.asInterface(b));
}});
+ registerService(Context.LIGHTS_SERVICE, LightsManager.class,
+ new CachedServiceFetcher<LightsManager>() {
+ @Override
+ public LightsManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new LightsManager(ctx);
+ }});
//TODO(b/136132412): refactor this: 1) merge IIncrementalManager.aidl and
//IIncrementalManagerNative.aidl, 2) implement the binder interface in
//IncrementalManagerService.java, 3) use JNI to call native functions
@@ -1306,6 +1321,7 @@ public final class SystemServiceRegistry {
TelephonyFrameworkInitializer.registerServiceWrappers();
AppSearchManagerFrameworkInitializer.initialize();
WifiFrameworkInitializer.registerServiceWrappers();
+ StatsFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
new file mode 100644
index 000000000000..22cc14bd5ed6
--- /dev/null
+++ b/core/java/android/app/WindowContext.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerImpl;
+
+/**
+ * {@link WindowContext} is a context for non-activity windows such as
+ * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system
+ * windows. Its resources and configuration are adjusted to the area of the display that will be
+ * used when a new window is added via {@link android.view.WindowManager.addView}.
+ *
+ * @see Context#createWindowContext(int)
+ * @hide
+ */
+// TODO(b/128338354): Handle config/display changes from server side.
+public class WindowContext extends ContextWrapper {
+ private final WindowManagerImpl mWindowManager;
+ private final IWindowManager mWms;
+ private final IBinder mToken;
+ private final int mDisplayId;
+ private boolean mOwnsToken;
+
+ /**
+ * Default constructor. Can either accept an existing token or generate one and registers it
+ * with the server if necessary.
+ *
+ * @param base Base {@link Context} for this new instance.
+ * @param token A valid {@link com.android.server.wm.WindowToken}. Pass {@code null} to generate
+ * one.
+ * @param type Window type to be used with this context.
+ * @hide
+ */
+ public WindowContext(Context base, IBinder token, int type) {
+ super(null /* base */);
+
+ mWms = WindowManagerGlobal.getWindowManagerService();
+ if (token != null && !isWindowToken(token)) {
+ throw new IllegalArgumentException("Token must be registered to server.");
+ }
+
+ final ContextImpl contextImpl = createBaseWindowContext(base, token);
+ attachBaseContext(contextImpl);
+ contextImpl.setOuterContext(this);
+
+ mToken = token != null ? token : new Binder();
+ mDisplayId = getDisplayId();
+ mWindowManager = new WindowManagerImpl(this);
+ mWindowManager.setDefaultToken(mToken);
+
+ // TODO(b/128338354): Obtain the correct config from WM and adjust resources.
+ if (token != null) {
+ mOwnsToken = false;
+ return;
+ }
+ try {
+ mWms.addWindowContextToken(mToken, type, mDisplayId, getPackageName());
+ // TODO(window-context): remove token with a DeathObserver
+ } catch (RemoteException e) {
+ mOwnsToken = false;
+ throw e.rethrowFromSystemServer();
+ }
+ mOwnsToken = true;
+ }
+
+ /** Check if the passed window token is registered with the server. */
+ private boolean isWindowToken(@NonNull IBinder token) {
+ try {
+ return mWms.isWindowToken(token);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ private static ContextImpl createBaseWindowContext(Context outer, IBinder token) {
+ final ContextImpl contextImpl = ContextImpl.getImpl(outer);
+ return contextImpl.createBaseWindowContext(token);
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (WINDOW_SERVICE.equals(name)) {
+ return mWindowManager;
+ }
+ return super.getSystemService(name);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mOwnsToken) {
+ try {
+ mWms.removeWindowToken(mToken, mDisplayId);
+ mOwnsToken = false;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ super.finalize();
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1bf6c99233e5..fa9dd274488f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2391,6 +2391,28 @@ public class DevicePolicyManager {
"android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
/**
+ * Return value for {@link #getPersonalAppsSuspendedReasons} when personal apps are not
+ * suspended.
+ */
+ public static final int PERSONAL_APPS_NOT_SUSPENDED = 0;
+
+ /**
+ * Flag for {@link #getPersonalAppsSuspendedReasons} return value. Set when personal
+ * apps are suspended by an admin explicitly via {@link #setPersonalAppsSuspended}.
+ */
+ public static final int PERSONAL_APPS_SUSPENDED_EXPLICITLY = 1 << 0;
+
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "PERSONAL_APPS_" }, value = {
+ PERSONAL_APPS_NOT_SUSPENDED,
+ PERSONAL_APPS_SUSPENDED_EXPLICITLY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PersonalAppSuspensionReason {}
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -4577,6 +4599,18 @@ public class DevicePolicyManager {
= "android.app.action.START_ENCRYPTION";
/**
+ * Activity action: launch the DPC to check policy compliance. This intent is launched when
+ * the user taps on the notification about personal apps suspension. When handling this intent
+ * the DPC must check if personal apps should still be suspended and either unsuspend them or
+ * instruct the user on how to resolve the noncompliance causing the suspension.
+ *
+ * @see #setPersonalAppsSuspended
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CHECK_POLICY_COMPLIANCE =
+ "android.app.action.CHECK_POLICY_COMPLIANCE";
+
+ /**
* Broadcast action: notify managed provisioning that new managed user is created.
*
* @hide
@@ -8226,6 +8260,11 @@ public class DevicePolicyManager {
* actual package file remain. This function can be called by a device owner, profile owner, or
* by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
* {@link #setDelegatedScopes}.
+ * <p>
+ * This method can be called on the {@link DevicePolicyManager} instance, returned by
+ * {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner
+ * of an organization-owned managed profile and the package must be a system package. If called
+ * on the parent instance, then the package is hidden or unhidden in the personal profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if the caller is a package access delegate.
@@ -8233,17 +8272,20 @@ public class DevicePolicyManager {
* @param hidden {@code true} if the package should be hidden, {@code false} if it should be
* unhidden.
* @return boolean Whether the hidden setting of the package was successfully updated.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or if called on
+ * the parent profile and the {@code admin} is not a profile owner of an
+ * organization-owned managed profile.
+ * @throws IllegalArgumentException if called on the parent profile and the package provided
+ * is not a system package.
* @see #setDelegatedScopes
* @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
boolean hidden) {
- throwIfParentInstance("setApplicationHidden");
if (mService != null) {
try {
return mService.setApplicationHidden(admin, mContext.getPackageName(), packageName,
- hidden);
+ hidden, mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8255,20 +8297,30 @@ public class DevicePolicyManager {
* Determine if a package is hidden. This function can be called by a device owner, profile
* owner, or by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via
* {@link #setDelegatedScopes}.
+ * <p>
+ * This method can be called on the {@link DevicePolicyManager} instance, returned by
+ * {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner
+ * of an organization-owned managed profile and the package must be a system package. If called
+ * on the parent instance, this will determine whether the package is hidden or unhidden in the
+ * personal profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if the caller is a package access delegate.
* @param packageName The name of the package to retrieve the hidden status of.
* @return boolean {@code true} if the package is hidden, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not a device or profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner or if called on
+ * the parent profile and the {@code admin} is not a profile owner of an
+ * organization-owned managed profile.
+ * @throws IllegalArgumentException if called on the parent profile and the package provided
+ * is not a system package.
* @see #setDelegatedScopes
* @see #DELEGATION_PACKAGE_ACCESS
*/
public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
- throwIfParentInstance("isApplicationHidden");
if (mService != null) {
try {
- return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName);
+ return mService.isApplicationHidden(admin, mContext.getPackageName(), packageName,
+ mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -9057,7 +9109,8 @@ public class DevicePolicyManager {
}
/**
- * Called by device owners to set a local system update policy. When a new policy is set,
+ * Called by device owners or profile owners of an organization-owned managed profile to to set
+ * a local system update policy. When a new policy is set,
* {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
* <p>
* If the supplied system update policy has freeze periods set but the freeze periods do not
@@ -9075,7 +9128,8 @@ public class DevicePolicyManager {
* components in the device owner package can set system update policies and the most
* recent policy takes effect.
* @param policy the new policy, or {@code null} to clear the current policy.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not a device owner or a profile owner of an
+ * organization-owned managed profile.
* @throws IllegalArgumentException if the policy type or maintenance window is not valid.
* @throws SystemUpdatePolicy.ValidationFailedException if the policy's freeze period does not
* meet the requirement.
@@ -9334,6 +9388,16 @@ public class DevicePolicyManager {
* {@link android.os.Build.VERSION_CODES#M} the app-op matching the permission is set to
* {@link android.app.AppOpsManager#MODE_IGNORED}, but the permission stays granted.
*
+ * NOTE: Starting from Android R, location-related permissions cannot be granted by the
+ * admin: Calling this method with {@link #PERMISSION_GRANT_STATE_GRANTED} for any of the
+ * following permissions will return false:
+ *
+ * <ul>
+ * <li>{@code ACCESS_FINE_LOCATION}</li>
+ * <li>{@code ACCESS_BACKGROUND_LOCATION}</li>
+ * <li>{@code ACCESS_COARSE_LOCATION}</li>
+ * </ul>
+ *
* @param admin Which profile or device owner this request is associated with.
* @param packageName The application to grant or revoke a permission to.
* @param permission The permission to grant or revoke.
@@ -11150,7 +11214,8 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to install a system update from the given file. The device will be
+ * Called by device owner or profile owner of an organization-owned managed profile to install
+ * a system update from the given file. The device will be
* rebooted in order to finish installing the update. Note that if the device is rebooted, this
* doesn't necessarily mean that the update has been applied successfully. The caller should
* additionally check the system version with {@link android.os.Build#FINGERPRINT} or {@link
@@ -11665,4 +11730,48 @@ public class DevicePolicyManager {
}
return false;
}
+
+ /**
+ * Called by profile owner of an organization-owned managed profile to check whether
+ * personal apps are suspended.
+ *
+ * @return a bitmask of reasons for personal apps suspension or
+ * {@link #PERSONAL_APPS_NOT_SUSPENDED} if apps are not suspended.
+ * @see #setPersonalAppsSuspended
+ */
+ public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons(
+ @NonNull ComponentName admin) {
+ throwIfParentInstance("getPersonalAppsSuspendedReasons");
+ if (mService != null) {
+ try {
+ return mService.getPersonalAppsSuspendedReasons(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Called by a profile owner of an organization-owned managed profile to suspend personal
+ * apps on the device. When personal apps are suspended the device can only be used for calls.
+ *
+ * <p>When personal apps are suspended, an ongoing notification about that is shown to the user.
+ * When the user taps the notification, system invokes {@link #ACTION_CHECK_POLICY_COMPLIANCE}
+ * in the profile owner package. Profile owner implementation that uses personal apps suspension
+ * must handle this intent.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+ * @param suspended Whether personal apps should be suspended.
+ */
+ public void setPersonalAppsSuspended(@NonNull ComponentName admin, boolean suspended) {
+ throwIfParentInstance("setPersonalAppsSuspended");
+ if (mService != null) {
+ try {
+ mService.setPersonalAppsSuspended(admin, suspended);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e7667c0a1b4a..3d6bf9db5535 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -233,8 +233,8 @@ interface IDevicePolicyManager {
boolean isNotificationListenerServicePermitted(in String packageName, int userId);
Intent createAdminSupportIntent(in String restriction);
- boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden);
- boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName);
+ boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent);
+ boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent);
UserHandle createAndManageUser(in ComponentName who, in String name, in ComponentName profileOwner, in PersistableBundle adminExtras, in int flags);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
@@ -470,4 +470,7 @@ interface IDevicePolicyManager {
void setCommonCriteriaModeEnabled(in ComponentName admin, boolean enabled);
boolean isCommonCriteriaModeEnabled(in ComponentName admin);
+
+ int getPersonalAppsSuspendedReasons(in ComponentName admin);
+ void setPersonalAppsSuspended(in ComponentName admin, boolean suspended);
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 3107c6302775..d4b5b1aab532 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -269,7 +269,7 @@ public final class CompanionDeviceManager {
@SystemApi
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
- public boolean isDeviceAssociated(
+ public boolean isDeviceAssociatedForWifiConnection(
@NonNull String packageName,
@NonNull MacAddress macAddress,
@NonNull UserHandle user) {
@@ -280,7 +280,7 @@ public final class CompanionDeviceManager {
Objects.requireNonNull(macAddress, "mac address cannot be null");
Objects.requireNonNull(user, "user cannot be null");
try {
- return mService.isDeviceAssociated(
+ return mService.isDeviceAssociatedForWifiConnection(
packageName, macAddress.toString(), user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 2e1ff0be8577..b323f58aa827 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -40,5 +40,6 @@ interface ICompanionDeviceManager {
boolean hasNotificationAccess(in ComponentName component);
PendingIntent requestNotificationAccess(in ComponentName component);
- boolean isDeviceAssociated(in String packageName, in String macAddress, int userId);
+ boolean isDeviceAssociatedForWifiConnection(in String packageName, in String macAddress,
+ int userId);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2943e398dd87..ebc5e0e4aa31 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3480,6 +3480,7 @@ public abstract class Context {
//@hide: TIME_DETECTOR_SERVICE,
//@hide: TIME_ZONE_DETECTOR_SERVICE,
PERMISSION_SERVICE,
+ LIGHTS_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3984,6 +3985,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
+ * android.net.ConnectivityDiagnosticsManager} for performing network connectivity diagnostics
+ * as well as receiving network connectivity information from the system.
+ *
+ * @see #getSystemService(String)
+ * @see android.net.ConnectivityDiagnosticsManager
+ */
+ public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link
* android.net.TestNetworkManager} for building TUNs and limited-use Networks
*
* @see #getSystemService(String)
@@ -5111,6 +5122,15 @@ public abstract class Context {
public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.hardware.lights.LightsManager} for controlling device lights.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String LIGHTS_SERVICE = "lights";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
@@ -5720,6 +5740,63 @@ public abstract class Context {
public abstract Context createDisplayContext(@NonNull Display display);
/**
+ * Creates a Context for a non-activity window.
+ *
+ * <p>
+ * A window context is a context that can be used to add non-activity windows, such as
+ * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}. A window context
+ * must be created from a context that has an associated {@link Display}, such as
+ * {@link android.app.Activity Activity} or a context created with
+ * {@link #createDisplayContext(Display)}.
+ *
+ * <p>
+ * The window context is created with the appropriate {@link Configuration} for the area of the
+ * display that the windows created with it can occupy; it must be used when
+ * {@link android.view.LayoutInflater inflating} views, such that they can be inflated with
+ * proper {@link Resources}.
+ *
+ * Below is a sample code to <b>add an application overlay window on the primary display:<b/>
+ * <pre class="prettyprint">
+ * ...
+ * final DisplayManager dm = anyContext.getSystemService(DisplayManager.class);
+ * final Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+ * final Context windowContext = anyContext.createDisplayContext(primaryDisplay)
+ * .createWindowContext(TYPE_APPLICATION_OVERLAY);
+ * final View overlayView = Inflater.from(windowContext).inflate(someLayoutXml, null);
+ *
+ * // WindowManager.LayoutParams initialization
+ * ...
+ * mParams.type = TYPE_APPLICATION_OVERLAY;
+ * ...
+ *
+ * mWindowContext.getSystemService(WindowManager.class).addView(overlayView, mParams);
+ * </pre>
+ *
+ * <p>
+ * This context's configuration and resources are adjusted to a display area where the windows
+ * with provided type will be added. <b>Note that all windows associated with the same context
+ * will have an affinity and can only be moved together between different displays or areas on a
+ * display.</b> If there is a need to add different window types, or non-associated windows,
+ * separate Contexts should be used.
+ * </p>
+ *
+ * @param type Window type in {@link WindowManager.LayoutParams}
+ * @return A {@link Context} that can be used to create windows.
+ * @throws UnsupportedOperationException if this is called on a non-UI context, such as
+ * {@link android.app.Application Application} or {@link android.app.Service Service}.
+ *
+ * @see #getSystemService(String)
+ * @see #getSystemService(Class)
+ * @see #WINDOW_SERVICE
+ * @see #LAYOUT_INFLATER_SERVICE
+ * @see #WALLPAPER_SERVICE
+ * @throws IllegalArgumentException if token is invalid
+ */
+ public @NonNull Context createWindowContext(int type) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Return a new Context object for the current Context but for a different feature in the app.
* Features can be used by complex apps to separate logical parts.
*
@@ -5803,17 +5880,22 @@ public abstract class Context {
public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
/**
+ * Get the display this context is associated with. Applications should use this method with
+ * {@link android.app.Activity} or a context associated with a {@link Display} via
+ * {@link #createDisplayContext(Display)} to get a display object associated with a Context, or
+ * {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id.
* @return Returns the {@link Display} object this context is associated with.
- * @hide
*/
- @UnsupportedAppUsage
- @TestApi
- public abstract Display getDisplay();
+ @Nullable
+ public Display getDisplay() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
/**
- * Gets the display ID.
+ * Gets the ID of the display this context is associated with.
*
* @return display ID associated with this {@link Context}.
+ * @see #getDisplay()
* @hide
*/
@TestApi
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6fe11873d327..b2b7988de896 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -977,6 +977,12 @@ public class ContextWrapper extends Context {
}
@Override
+ @NonNull
+ public Context createWindowContext(int type) {
+ return mBase.createWindowContext(type);
+ }
+
+ @Override
public @NonNull Context createFeatureContext(@Nullable String featureId) {
return mBase.createFeatureContext(featureId);
}
@@ -992,11 +998,8 @@ public class ContextWrapper extends Context {
return mBase.getDisplayAdjustments(displayId);
}
- /** @hide */
- @UnsupportedAppUsage
- @TestApi
@Override
- public Display getDisplay() {
+ public @Nullable Display getDisplay() {
return mBase.getDisplay();
}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index e86bb250c033..fc20263fe00a 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.IPackageInstallObserver2;
import android.content.IntentSender;
import android.os.ParcelFileDescriptor;
@@ -39,8 +40,9 @@ interface IPackageInstallerSession {
void transfer(in String packageName);
void abandon();
- void addFile(String name, long lengthBytes, in byte[] metadata);
- void removeFile(String name);
+ DataLoaderParamsParcel getDataLoaderParams();
+ void addFile(int location, String name, long lengthBytes, in byte[] metadata, in byte[] signature);
+ void removeFile(int location, String name);
boolean isMultiPackage();
int[] getChildSessionIds();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b3d8eb51e324..93126b8002ad 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -230,7 +230,7 @@ interface IPackageManager {
* @param versionedPackage The package to delete.
* @param observer a callback to use to notify when the package deletion in finished.
* @param userId the id of the user for whom to delete the package
- * @param flags - possible values: {@link #DONT_DELETE_DATA}
+ * @param flags - possible values: {@link #DELETE_KEEP_DATA}
*/
void deletePackageVersioned(in VersionedPackage versionedPackage,
IPackageDeleteObserver2 observer, int userId, int flags);
diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java
index ac5fd1e41075..111ad32d1e41 100644
--- a/core/java/android/content/pm/InstallationFile.java
+++ b/core/java/android/content/pm/InstallationFile.java
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,12 +32,14 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
+@SystemApi
public final class InstallationFile implements Parcelable {
public static final int FILE_TYPE_UNKNOWN = -1;
public static final int FILE_TYPE_APK = 0;
public static final int FILE_TYPE_LIB = 1;
public static final int FILE_TYPE_OBB = 2;
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"FILE_TYPE_"}, value = {
FILE_TYPE_APK,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f264adbbb592..b1b9454aeddd 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -365,6 +365,41 @@ public class PackageInstaller {
@SystemApi
public static final int DATA_LOADER_TYPE_INCREMENTAL = DataLoaderType.INCREMENTAL;
+ /**
+ * Target location for the file in installation session is /data/app/<packageName>-<id>.
+ * This is the intended location for APKs.
+ * Requires permission to install packages.
+ * {@hide}
+ */
+ @SystemApi
+ public static final int LOCATION_DATA_APP = 0;
+
+ /**
+ * Target location for the file in installation session is
+ * /data/media/<userid>/Android/obb/<packageName>. This is the intended location for OBBs.
+ * {@hide}
+ */
+ @SystemApi
+ public static final int LOCATION_MEDIA_OBB = 1;
+
+ /**
+ * Target location for the file in installation session is
+ * /data/media/<userid>/Android/data/<packageName>.
+ * This is the intended location for application data.
+ * Can only be used by an app itself running under specific user.
+ * {@hide}
+ */
+ @SystemApi
+ public static final int LOCATION_MEDIA_DATA = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "LOCATION_" }, value = {
+ LOCATION_DATA_APP,
+ LOCATION_MEDIA_OBB,
+ LOCATION_MEDIA_DATA})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FileLocation{}
+
private final IPackageInstaller mInstaller;
private final int mUserId;
private final String mInstallerPackageName;
@@ -1071,10 +1106,33 @@ public class PackageInstaller {
}
}
+ /**
+ * @return data loader params or null if the session is not using one.
+ *
+ * WARNING: This is a system API to aid internal development.
+ * Use at your own risk. It will change or be removed without warning.
+ * {@hide}
+ */
+ @SystemApi
+ public @Nullable DataLoaderParams getDataLoaderParams() {
+ try {
+ DataLoaderParamsParcel data = mSession.getDataLoaderParams();
+ if (data == null) {
+ return null;
+ }
+ return new DataLoaderParams(data);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* Adds a file to session. On commit this file will be pulled from dataLoader.
*
+ * @param location target location for the file. Possible values:
+ * {@link #LOCATION_DATA_APP},
+ * {@link #LOCATION_MEDIA_OBB},
+ * {@link #LOCATION_MEDIA_DATA}.
* @param name arbitrary, unique name of your choosing to identify the
* APK being written. You can open a file again for
* additional writes (such as after a reboot) by using the
@@ -1084,6 +1142,8 @@ public class PackageInstaller {
* The system may clear various caches as needed to allocate
* this space.
* @param metadata additional info use by dataLoader to pull data for the file.
+ * @param signature additional file signature, e.g.
+ * <a href="https://source.android.com/security/apksigning/v4.html">APK Signature Scheme v4</a>
* @throws SecurityException if called after the session has been
* sealed or abandoned
* @throws IllegalStateException if called for non-callback session
@@ -1093,9 +1153,10 @@ public class PackageInstaller {
* {@hide}
*/
@SystemApi
- public void addFile(@NonNull String name, long lengthBytes, @NonNull byte[] metadata) {
+ public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
+ @NonNull byte[] metadata, @Nullable byte[] signature) {
try {
- mSession.addFile(name, lengthBytes, metadata);
+ mSession.addFile(location, name, lengthBytes, metadata, signature);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1104,15 +1165,20 @@ public class PackageInstaller {
/**
* Removes a file.
*
+ * @param location target location for the file. Possible values:
+ * {@link #LOCATION_DATA_APP},
+ * {@link #LOCATION_MEDIA_OBB},
+ * {@link #LOCATION_MEDIA_DATA}.
* @param name name of a file, e.g. split.
* @throws SecurityException if called after the session has been
* sealed or abandoned
* @throws IllegalStateException if called for non-callback session
* {@hide}
*/
- public void removeFile(@NonNull String name) {
+ @SystemApi
+ public void removeFile(@FileLocation int location, @NonNull String name) {
try {
- mSession.removeFile(name);
+ mSession.removeFile(location, name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2029,6 +2095,9 @@ public class PackageInstaller {
public boolean isCommitted;
/** {@hide} */
+ public long createdMillis;
+
+ /** {@hide} */
public long updatedMillis;
/** {@hide} */
@@ -2078,6 +2147,7 @@ public class PackageInstaller {
mStagedSessionErrorMessage = source.readString();
isCommitted = source.readBoolean();
rollbackDataPolicy = source.readInt();
+ createdMillis = source.readLong();
}
/**
@@ -2520,6 +2590,13 @@ public class PackageInstaller {
}
/**
+ * The timestamp of the initial creation of the session.
+ */
+ public long getCreatedMillis() {
+ return createdMillis;
+ }
+
+ /**
* The timestamp of the last update that occurred to the session, including changing of
* states in case of staged sessions.
*/
@@ -2568,6 +2645,7 @@ public class PackageInstaller {
dest.writeString(mStagedSessionErrorMessage);
dest.writeBoolean(isCommitted);
dest.writeInt(rollbackDataPolicy);
+ dest.writeLong(createdMillis);
}
public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fe5e67234fc4..9f8d32b96b6d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -369,7 +369,7 @@ public abstract class PackageManager {
* Flag parameter to retrieve some information about all applications (even
* uninstalled ones) which have data directories. This state could have
* resulted if applications have been deleted with flag
- * {@code DONT_DELETE_DATA} with a possibility of being replaced or
+ * {@code DELETE_KEEP_DATA} with a possibility of being replaced or
* reinstalled in future.
* <p>
* Note: this flag may cause less information about currently installed
@@ -2203,6 +2203,23 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the feature version
+ * specifies a date such that the device is known to pass the Vulkan dEQP test suite associated
+ * with that date. The date is encoded as follows:
+ * <ul>
+ * <li>Year in bits 31-16</li>
+ * <li>Month in bits 15-8</li>
+ * <li>Day in bits 7-0</li>
+ * </ul>
+ * <p>
+ * Example: 2019-03-01 is encoded as 0x07E30301, and would indicate that the device passes the
+ * Vulkan dEQP test suite version that was current on 2019-03-01.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VULKAN_DEQP_LEVEL = "android.software.vulkan.deqp.level";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device includes broadcast radio tuner.
* @hide
*/
@@ -3311,6 +3328,15 @@ public abstract class PackageManager {
public static final int FLAG_PERMISSION_ONE_TIME = 1 << 16;
/**
+ * Permission flags: Reserved for use by the permission controller.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = 1 << 28 | 1 << 29
+ | 1 << 30 | 1 << 31;
+
+ /**
* Permission flags: Bitwise or of all permission flags allowing an
* exemption for a restricted permission.
* @hide
@@ -3517,7 +3543,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
@@ -3543,7 +3569,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
@@ -3564,7 +3590,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
* @hide
@@ -3811,7 +3837,7 @@ public abstract class PackageManager {
* the application information is retrieved from the list of
* uninstalled applications (which includes installed applications
* as well as applications with data directory i.e. applications
- * which had been deleted with {@code DONT_DELETE_DATA} flag set).
+ * which had been deleted with {@code DELETE_KEEP_DATA} flag set).
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
@@ -3838,7 +3864,7 @@ public abstract class PackageManager {
* the application information is retrieved from the list of
* uninstalled applications (which includes installed applications
* as well as applications with data directory i.e. applications
- * which had been deleted with {@code DONT_DELETE_DATA} flag set).
+ * which had been deleted with {@code DELETE_KEEP_DATA} flag set).
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
* @hide
@@ -3961,7 +3987,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
*/
@NonNull
public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
@@ -3979,7 +4005,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
*/
@NonNull
public abstract List<PackageInfo> getPackagesHoldingPermissions(
@@ -3998,7 +4024,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
* @hide
*/
@NonNull
@@ -4544,7 +4570,7 @@ public abstract class PackageManager {
/**
* Return a List of all application packages that are installed for the
* current user. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all
- * applications including those deleted with {@code DONT_DELETE_DATA}
+ * applications including those deleted with {@code DELETE_KEEP_DATA}
* (partially installed apps with data directory) will be returned.
*
* @param flags Additional option flags to modify the data returned.
@@ -4555,7 +4581,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
*/
@NonNull
public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
@@ -4564,7 +4590,7 @@ public abstract class PackageManager {
* Return a List of all application packages that are installed on the
* device, for a specific user. If flag GET_UNINSTALLED_PACKAGES has been
* set, a list of all applications including those deleted with
- * {@code DONT_DELETE_DATA} (partially installed apps with data directory)
+ * {@code DELETE_KEEP_DATA} (partially installed apps with data directory)
* will be returned.
*
* @param flags Additional option flags to modify the data returned.
@@ -4577,7 +4603,7 @@ public abstract class PackageManager {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
* @hide
*/
@NonNull
diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java
new file mode 100644
index 000000000000..c77a267958f5
--- /dev/null
+++ b/core/java/android/content/pm/ProcessInfo.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+/**
+ * Information about a process an app may run. This corresponds to information collected from the
+ * AndroidManifest.xml's &lt;permission-group&gt; tags.
+ * @hide
+ */
+public class ProcessInfo implements Parcelable {
+ /**
+ * The name of the process, fully-qualified based on the app's package name.
+ */
+ public String name;
+
+ /**
+ * If non-null, these are permissions that are not allowed in this process.
+ */
+ @Nullable
+ public ArraySet<String> deniedPermissions;
+
+ public ProcessInfo(String name, ArraySet<String> deniedPermissions) {
+ this.name = name;
+ this.deniedPermissions = deniedPermissions;
+ }
+
+ @Deprecated
+ public ProcessInfo(@NonNull ProcessInfo orig) {
+ this.name = orig.name;
+ this.deniedPermissions = orig.deniedPermissions;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(this.name);
+ final int numDenied = this.deniedPermissions != null
+ ? this.deniedPermissions.size() : 0;
+ dest.writeInt(numDenied);
+ for (int i = 0; i < numDenied; i++) {
+ dest.writeString(this.deniedPermissions.valueAt(i));
+ }
+ }
+
+ public static final @NonNull Creator<ProcessInfo> CREATOR =
+ new Creator<ProcessInfo>() {
+ public ProcessInfo createFromParcel(Parcel source) {
+ return new ProcessInfo(source);
+ }
+ public ProcessInfo[] newArray(int size) {
+ return new ProcessInfo[size];
+ }
+ };
+
+ private ProcessInfo(Parcel source) {
+ this.name = source.readString();
+ final int numDenied = source.readInt();
+ if (numDenied > 0) {
+ this.deniedPermissions = new ArraySet<>(numDenied);
+ for (int i = numDenied - 1; i >= 0; i--) {
+ this.deniedPermissions.add(TextUtils.safeIntern(source.readString()));
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 990c8359e698..fbe5a48ad61e 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -36,6 +36,7 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -379,6 +380,9 @@ public interface AndroidPackage extends Parcelable {
@Nullable
long[] getUsesStaticLibrariesVersions();
+ @Nullable
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses();
+
int getVersionCode();
int getVersionCodeMajor();
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 9b069acd1b06..3018230fac27 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -2426,6 +2426,21 @@ public class ApkParseUtils {
XmlUtils.skipCurrentTag(parser);
break;
+ case "processes":
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> processes =
+ ComponentParseUtils.parseProcesses(separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError);
+ if (processes == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.setProcesses(processes);
+ break;
case "uses-package":
// Dependencies for app installers; we don't currently try to
// enforce this.
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 3846202aa04d..9a0a6d54da50 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -50,6 +50,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
@@ -1366,6 +1367,72 @@ public class ComponentParseUtils {
};
}
+ public static class ParsedProcess implements Parcelable {
+
+ public String name;
+ @Nullable
+ public ArraySet<String> deniedPermissions;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.name);
+ final int numDenied = this.deniedPermissions != null
+ ? this.deniedPermissions.size() : 0;
+ dest.writeInt(numDenied);
+ for (int i = 0; i < numDenied; i++) {
+ dest.writeString(this.deniedPermissions.valueAt(i));
+ }
+ }
+
+ public ParsedProcess() {
+ }
+
+ public ParsedProcess(@NonNull ParsedProcess other) {
+ name = other.name;
+ if (other.deniedPermissions != null) {
+ deniedPermissions = new ArraySet<>(other.deniedPermissions);
+ }
+ }
+
+ public void addStateFrom(@NonNull ParsedProcess other) {
+ if (other.deniedPermissions != null) {
+ for (int i = other.deniedPermissions.size() - 1; i >= 0; i--) {
+ if (deniedPermissions == null) {
+ deniedPermissions = new ArraySet<>(other.deniedPermissions.size());
+ }
+ deniedPermissions.add(other.deniedPermissions.valueAt(i));
+ }
+ }
+ }
+
+ protected ParsedProcess(Parcel in) {
+ this.name = TextUtils.safeIntern(in.readString());
+ final int numDenied = in.readInt();
+ if (numDenied > 0) {
+ this.deniedPermissions = new ArraySet<>(numDenied);
+ this.deniedPermissions.add(TextUtils.safeIntern(in.readString()));
+ }
+ }
+
+ public static final Creator<ParsedProcess> CREATOR =
+ new Creator<ParsedProcess>() {
+ @Override
+ public ParsedProcess createFromParcel(Parcel source) {
+ return new ParsedProcess(source);
+ }
+
+ @Override
+ public ParsedProcess[] newArray(int size) {
+ return new ParsedProcess[size];
+ }
+ };
+ }
+
public static ParsedActivity parseActivity(
String[] separateProcesses,
ParsingPackage parsingPackage,
@@ -3266,6 +3333,189 @@ public class ComponentParseUtils {
return result;
}
+ private static @Nullable ArraySet<String> parseDenyPermission(
+ ArraySet<String> perms,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission);
+ if (sa == null) {
+ outError[0] = "<deny-permission> could not be parsed";
+ return null;
+ }
+
+ try {
+ String perm = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestDenyPermission_name,0);
+ if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) {
+ if (perms == null) {
+ perms = new ArraySet<>();
+ }
+ perms.add(perm);
+ }
+ } finally {
+ sa.recycle();
+ }
+ XmlUtils.skipCurrentTag(parser);
+ return perms;
+ }
+
+ private static ArraySet<String> parseAllowPermission(
+ ArraySet<String> perms,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission);
+ if (sa == null) {
+ outError[0] = "<allow-permission> could not be parsed";
+ return null;
+ }
+
+ try {
+ String perm = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestAllowPermission_name,0);
+ if (perm != null && perm.equals(android.Manifest.permission.INTERNET)
+ && perms != null) {
+ perms.remove(perm);
+ if (perms.size() <= 0) {
+ perms = null;
+ }
+ }
+ } finally {
+ sa.recycle();
+ }
+ XmlUtils.skipCurrentTag(parser);
+ return perms;
+ }
+
+ public static ParsedProcess parseProcess(
+ ArraySet<String> perms,
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess);
+ if (sa == null) {
+ outError[0] = "<process> could not be parsed";
+ return null;
+ }
+
+ ParsedProcess proc = new ParsedProcess();
+ if (perms != null) {
+ proc.deniedPermissions = new ArraySet(perms);
+ }
+
+ try {
+ proc.name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProcess_process,0);
+ proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
+ null, proc.name, flags, separateProcesses, outError);
+
+ if (proc.name == null || proc.name.length() <= 0) {
+ outError[0] = "<process> does not specify android:process";
+ return null;
+ }
+ proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
+ parsingPackage.getPackageName(), proc.name,
+ flags, separateProcesses, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } finally {
+ sa.recycle();
+ }
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("deny-permission")) {
+ proc.deniedPermissions = parseDenyPermission(proc.deniedPermissions, res, parser,
+ outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("allow-permission")) {
+ proc.deniedPermissions = parseAllowPermission(proc.deniedPermissions, res, parser,
+ outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else {
+ Slog.w(TAG, "Unknown element under <process>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ return proc;
+ }
+
+ public static ArrayMap<String, ParsedProcess> parseProcesses(
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ ArraySet<String> deniedPerms = null;
+ ArrayMap<String, ParsedProcess> processes = new ArrayMap<>();
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("deny-permission")) {
+ deniedPerms = parseDenyPermission(deniedPerms, res, parser, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("allow-permission")) {
+ deniedPerms = parseAllowPermission(deniedPerms, res, parser, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("process")) {
+ ParsedProcess proc = parseProcess(deniedPerms, separateProcesses, parsingPackage,
+ res, parser, flags, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ if (processes.get(proc.name) != null) {
+ outError[0] = "<process> specified existing name '" + proc.name + "'";
+ return null;
+ }
+ processes.put(proc.name, proc);
+ } else {
+ Slog.w(TAG, "Unknown element under <processes>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ return processes;
+ }
+
public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
TypedArray sw = res.obtainAttributes(attrs,
R.styleable.AndroidManifestLayout);
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 8677fced18fa..9baf3258a230 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -215,6 +215,9 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
@Nullable
private ArrayList<String> queriesPackages;
+ @Nullable
+ private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
+
private String[] splitClassLoaderNames;
private String[] splitCodePaths;
private SparseArray<int[]> splitDependencies;
@@ -527,6 +530,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
return usesStaticLibraries;
}
+ @Nullable
+ @Override
+ public ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses() {
+ return processes;
+ }
+
@Override
public boolean isBaseHardwareAccelerated() {
return baseHardwareAccelerated;
@@ -948,6 +957,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
}
@Override
+ public PackageImpl setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes) {
+ this.processes = processes;
+ return this;
+ }
+
+ @Override
public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
if (supportsSmallScreens == 1) {
return this;
@@ -3010,6 +3025,11 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
dest.writeStringList(this.usesOptionalLibraries);
dest.writeStringList(this.usesStaticLibraries);
dest.writeLongArray(this.usesStaticLibrariesVersions);
+ final int numProcesses = this.processes != null ? this.processes.size() : 0;
+ dest.writeInt(numProcesses);
+ for (int i = 0; i < numProcesses; i++) {
+ this.processes.valueAt(i).writeToParcel(dest, 0);
+ }
if (this.usesStaticLibrariesCertDigests == null) {
dest.writeInt(-1);
@@ -3161,6 +3181,16 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
this.usesStaticLibraries = in.createStringArrayList();
internStringArrayList(usesStaticLibraries);
this.usesStaticLibrariesVersions = in.createLongArray();
+ final int numProcesses = in.readInt();
+ if (numProcesses > 0) {
+ this.processes = new ArrayMap<>(numProcesses);
+ for (int i = 0; i < numProcesses; i++) {
+ ComponentParseUtils.ParsedProcess proc = new ComponentParseUtils.ParsedProcess(in);
+ this.processes.put(proc.name, proc);
+ }
+ } else {
+ this.processes = null;
+ }
int digestsSize = in.readInt();
if (digestsSize >= 0) {
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
index e0ba99bb4937..72df18998470 100644
--- a/core/java/android/content/pm/parsing/PackageInfoUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -32,6 +32,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
@@ -41,11 +42,11 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
-import java.util.LinkedHashSet;
import java.util.Set;
/** @hide */
@@ -459,6 +460,24 @@ public class PackageInfoUtils {
return ii;
}
+ public static ArrayMap<String, ProcessInfo> generateProcessInfo(
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> procs,
+ @PackageManager.ComponentInfoFlags int flags) {
+ if (procs == null) {
+ return null;
+ }
+
+ final int numProcs = procs.size();
+ ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs);
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
+ retProcs.put(proc.name, new ProcessInfo(proc.name,
+ proc.deniedPermissions != null
+ ? new ArraySet<>(proc.deniedPermissions) : null));
+ }
+ return retProcs;
+ }
+
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
@PackageManager.ComponentInfoFlags int flags) {
if (p == null) return null;
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 411c74991594..9ddcc0995fd4 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -31,6 +31,7 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.os.Bundle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -99,6 +100,8 @@ public interface ParsingPackage extends AndroidPackage {
ParsingPackage addQueriesPackage(String packageName);
+ ParsingPackage setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes);
+
ParsingPackage asSplit(
String[] splitNames,
String[] splitCodePaths,
diff --git a/core/java/android/hardware/CameraStatus.java b/core/java/android/hardware/CameraStatus.java
index 08b5b776c94e..29802cb33c38 100644
--- a/core/java/android/hardware/CameraStatus.java
+++ b/core/java/android/hardware/CameraStatus.java
@@ -30,6 +30,7 @@ import android.os.Parcelable;
public class CameraStatus implements Parcelable {
public String cameraId;
public int status;
+ public String[] unavailablePhysicalCameras;
@Override
public int describeContents() {
@@ -40,11 +41,13 @@ public class CameraStatus implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(cameraId);
out.writeInt(status);
+ out.writeStringArray(unavailablePhysicalCameras);
}
public void readFromParcel(Parcel in) {
cameraId = in.readString();
status = in.readInt();
+ unavailablePhysicalCameras = in.readStringArray();
}
public static final @android.annotation.NonNull Parcelable.Creator<CameraStatus> CREATOR =
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 9b58578e3811..55025f0411f9 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -718,6 +718,52 @@ public final class CameraManager {
public void onCameraAccessPrioritiesChanged() {
// default empty implementation
}
+
+ /**
+ * A physical camera has become available for use again.
+ *
+ * <p>By default, all of the physical cameras of a logical multi-camera are
+ * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical
+ * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical
+ * multi-camera is invoked. However, if some specific physical cameras are unavailable
+ * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
+ * {@link #onCameraAvailable}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the logical multi-camera.
+ * @param physicalCameraId The unique identifier of the physical camera.
+ *
+ * @see #onCameraAvailable
+ * @see #onPhysicalCameraUnavailable
+ */
+ public void onPhysicalCameraAvailable(@NonNull String cameraId,
+ @NonNull String physicalCameraId) {
+ // default empty implementation
+ }
+
+ /**
+ * A previously-available physical camera has become unavailable for use.
+ *
+ * <p>By default, all of the physical cameras of a logical multi-camera are
+ * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical
+ * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical
+ * multi-camera is invoked. If some specific physical cameras are unavailable
+ * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
+ * {@link #onCameraAvailable}.</p>
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the logical multi-camera.
+ * @param physicalCameraId The unique identifier of the physical camera.
+ *
+ * @see #onCameraAvailable
+ * @see #onPhysicalCameraAvailable
+ */
+ public void onPhysicalCameraUnavailable(@NonNull String cameraId,
+ @NonNull String physicalCameraId) {
+ // default empty implementation
+ }
}
/**
@@ -914,6 +960,9 @@ public final class CameraManager {
private final ScheduledExecutorService mScheduler = Executors.newScheduledThreadPool(1);
// Camera ID -> Status map
private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
+ // Camera ID -> (physical camera ID -> Status map)
+ private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices =
+ new ArrayMap<String, ArrayList<String>>();
// Registered availablility callbacks and their executors
private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap =
@@ -1003,6 +1052,14 @@ public final class CameraManager {
CameraStatus[] cameraStatuses = cameraService.addListener(this);
for (CameraStatus c : cameraStatuses) {
onStatusChangedLocked(c.status, c.cameraId);
+
+ if (c.unavailablePhysicalCameras != null) {
+ for (String unavailPhysicalCamera : c.unavailablePhysicalCameras) {
+ onPhysicalCameraStatusChangedLocked(
+ ICameraServiceListener.STATUS_NOT_PRESENT,
+ c.cameraId, unavailPhysicalCamera);
+ }
+ }
}
mCameraService = cameraService;
} catch(ServiceSpecificException e) {
@@ -1086,6 +1143,10 @@ public final class CameraManager {
public void onStatusChanged(int status, String id) throws RemoteException {
}
@Override
+ public void onPhysicalCameraStatusChanged(int status,
+ String id, String physicalId) throws RemoteException {
+ }
+ @Override
public void onTorchStatusChanged(int status, String id) throws RemoteException {
}
@Override
@@ -1236,7 +1297,7 @@ public final class CameraManager {
}
private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
- final String id, final int status) {
+ final String id, final String physicalId, final int status) {
if (isAvailable(status)) {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1244,7 +1305,11 @@ public final class CameraManager {
new Runnable() {
@Override
public void run() {
- callback.onCameraAvailable(id);
+ if (physicalId == null) {
+ callback.onCameraAvailable(id);
+ } else {
+ callback.onPhysicalCameraAvailable(id, physicalId);
+ }
}
});
} finally {
@@ -1257,7 +1322,11 @@ public final class CameraManager {
new Runnable() {
@Override
public void run() {
- callback.onCameraUnavailable(id);
+ if (physicalId == null) {
+ callback.onCameraUnavailable(id);
+ } else {
+ callback.onPhysicalCameraUnavailable(id, physicalId);
+ }
}
});
} finally {
@@ -1304,7 +1373,16 @@ public final class CameraManager {
for (int i = 0; i < mDeviceStatus.size(); i++) {
String id = mDeviceStatus.keyAt(i);
Integer status = mDeviceStatus.valueAt(i);
- postSingleUpdate(callback, executor, id, status);
+ postSingleUpdate(callback, executor, id, null /*physicalId*/, status);
+
+ // Send the NOT_PRESENT state for unavailable physical cameras
+ if (isAvailable(status) && mUnavailablePhysicalDevices.containsKey(id)) {
+ ArrayList<String> unavailableIds = mUnavailablePhysicalDevices.get(id);
+ for (String unavailableId : unavailableIds) {
+ postSingleUpdate(callback, executor, id, unavailableId,
+ ICameraServiceListener.STATUS_NOT_PRESENT);
+ }
+ }
}
}
@@ -1323,8 +1401,12 @@ public final class CameraManager {
Integer oldStatus;
if (status == ICameraServiceListener.STATUS_NOT_PRESENT) {
oldStatus = mDeviceStatus.remove(id);
+ mUnavailablePhysicalDevices.remove(id);
} else {
oldStatus = mDeviceStatus.put(id, status);
+ if (oldStatus == null) {
+ mUnavailablePhysicalDevices.put(id, new ArrayList<String>());
+ }
}
if (oldStatus != null && oldStatus == status) {
@@ -1366,10 +1448,62 @@ public final class CameraManager {
Executor executor = mCallbackMap.valueAt(i);
final AvailabilityCallback callback = mCallbackMap.keyAt(i);
- postSingleUpdate(callback, executor, id, status);
+ postSingleUpdate(callback, executor, id, null /*physicalId*/, status);
}
} // onStatusChangedLocked
+ private void onPhysicalCameraStatusChangedLocked(int status,
+ String id, String physicalId) {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format("Camera id %s physical camera id %s has status "
+ + "changed to 0x%x", id, physicalId, status));
+ }
+
+ if (!validStatus(status)) {
+ Log.e(TAG, String.format(
+ "Ignoring invalid device %s physical device %s status 0x%x", id,
+ physicalId, status));
+ return;
+ }
+
+ //TODO: Do we need to treat this as error?
+ if (!mDeviceStatus.containsKey(id) || !isAvailable(mDeviceStatus.get(id))
+ || !mUnavailablePhysicalDevices.containsKey(id)) {
+ Log.e(TAG, String.format("Camera %s is not available. Ignore physical camera "
+ + "status change", id));
+ return;
+ }
+
+ ArrayList<String> unavailablePhysicalDevices = mUnavailablePhysicalDevices.get(id);
+ if (!isAvailable(status)
+ && !unavailablePhysicalDevices.contains(physicalId)) {
+ unavailablePhysicalDevices.add(physicalId);
+ } else if (isAvailable(status)
+ && unavailablePhysicalDevices.contains(physicalId)) {
+ unavailablePhysicalDevices.remove(physicalId);
+ } else {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format(
+ "Physical camera device status was previously available (%b), "
+ + " and is now again available (%b)"
+ + "so no new client visible update will be sent",
+ !unavailablePhysicalDevices.contains(physicalId),
+ isAvailable(status)));
+ }
+ return;
+ }
+
+ final int callbackCount = mCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Executor executor = mCallbackMap.valueAt(i);
+ final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+ postSingleUpdate(callback, executor, id, physicalId, status);
+ }
+ } // onPhysicalCameraStatusChangedLocked
+
private void updateTorchCallbackLocked(TorchCallback callback, Executor executor) {
for (int i = 0; i < mTorchStatus.size(); i++) {
String id = mTorchStatus.keyAt(i);
@@ -1478,6 +1612,14 @@ public final class CameraManager {
}
@Override
+ public void onPhysicalCameraStatusChanged(int status, String cameraId,
+ String physicalCameraId) throws RemoteException {
+ synchronized (mLock) {
+ onPhysicalCameraStatusChangedLocked(status, cameraId, physicalCameraId);
+ }
+ }
+
+ @Override
public void onTorchStatusChanged(int status, String cameraId) throws RemoteException {
synchronized (mLock) {
onTorchStatusChangedLocked(status, cameraId);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 89dac2aef68f..4dd3a30e046c 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -865,14 +865,20 @@ public abstract class CameraMetadata<TKey> {
* <p>The camera device is a logical camera backed by two or more physical cameras.</p>
* <p>In API level 28, the physical cameras must also be exposed to the application via
* {@link android.hardware.camera2.CameraManager#getCameraIdList }.</p>
- * <p>Starting from API level 29, some or all physical cameras may not be independently
- * exposed to the application, in which case the physical camera IDs will not be
- * available in {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the
+ * <p>Starting from API level 29:</p>
+ * <ul>
+ * <li>Some or all physical cameras may not be independently exposed to the application,
+ * in which case the physical camera IDs will not be available in
+ * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the
* application can still query the physical cameras' characteristics by calling
- * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. Additionally,
- * if a physical camera is hidden from camera ID list, the mandatory stream combinations
- * for that physical camera must be supported through the logical camera using physical
- * streams.</p>
+ * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</li>
+ * <li>If a physical camera is hidden from camera ID list, the mandatory stream
+ * combinations for that physical camera must be supported through the logical camera
+ * using physical streams. One exception is that in API level 30, a physical camera
+ * may become unavailable via
+ * {@link CameraManager.AvailabilityCallback#onPhysicalCameraUnavailable }
+ * callback.</li>
+ * </ul>
* <p>Combinations of logical and physical streams, or physical streams from different
* physical cameras are not guaranteed. However, if the camera device supports
* {@link CameraDevice#isSessionConfigurationSupported },
diff --git a/core/java/android/hardware/lights/ILightsManager.aidl b/core/java/android/hardware/lights/ILightsManager.aidl
new file mode 100644
index 000000000000..6ea24b74a4a3
--- /dev/null
+++ b/core/java/android/hardware/lights/ILightsManager.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+
+/**
+ * API to lights manager service.
+ *
+ * {@hide}
+ */
+interface ILightsManager {
+ List<Light> getLights();
+ LightState getLightState(int lightId);
+ void openSession(in IBinder sessionToken);
+ void closeSession(in IBinder sessionToken);
+ void setLightStates(in IBinder sessionToken, in int[] lightIds, in LightState[] states);
+}
diff --git a/core/java/android/hardware/lights/Light.aidl b/core/java/android/hardware/lights/Light.aidl
new file mode 100644
index 000000000000..946e06d44cf3
--- /dev/null
+++ b/core/java/android/hardware/lights/Light.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+/** @hide */
+parcelable Light;
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
new file mode 100644
index 000000000000..c5cb8037d4db
--- /dev/null
+++ b/core/java/android/hardware/lights/Light.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a logical light on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class Light implements Parcelable {
+ private final int mId;
+ private final int mOrdinal;
+ private final int mType;
+
+ /**
+ * Creates a new light with the given data.
+ *
+ * @hide */
+ public Light(int id, int ordinal, int type) {
+ mId = id;
+ mOrdinal = ordinal;
+ mType = type;
+ }
+
+ private Light(@NonNull Parcel in) {
+ mId = in.readInt();
+ mOrdinal = in.readInt();
+ mType = in.readInt();
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeInt(mOrdinal);
+ dest.writeInt(mType);
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @android.annotation.NonNull Parcelable.Creator<Light> CREATOR =
+ new Parcelable.Creator<Light>() {
+ public Light createFromParcel(Parcel in) {
+ return new Light(in);
+ }
+
+ public Light[] newArray(int size) {
+ return new Light[size];
+ }
+ };
+
+ /**
+ * Returns the id of the light.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the ordinal of the light.
+ *
+ * <p>This represents the physical order of the lights on the device. The exact values are
+ * device-dependent, but for example, if there are lights in a row, sorting the Light objects
+ * by ordinal should match the order in which they appear on the device. If the device has
+ * 4 lights, the ordinals could be [1, 2, 3, 4] or [0, 10, 20, 30] or any other values that
+ * have the same sort order.
+ */
+ public int getOrdinal() {
+ return mOrdinal;
+ }
+
+ /**
+ * Returns the logical type of the light.
+ */
+ public @LightsManager.LightType int getType() {
+ return mType;
+ }
+}
diff --git a/core/java/android/hardware/lights/LightState.aidl b/core/java/android/hardware/lights/LightState.aidl
new file mode 100644
index 000000000000..d598336ae40c
--- /dev/null
+++ b/core/java/android/hardware/lights/LightState.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+/** @hide */
+parcelable LightState;
diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java
new file mode 100644
index 000000000000..e55aa702f15c
--- /dev/null
+++ b/core/java/android/hardware/lights/LightState.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the state of a device light.
+ *
+ * <p>Controlling the color and brightness of a light is done on a best-effort basis. Each of the R,
+ * G and B channels represent the intensities of the respective part of an RGB LED, if that is
+ * supported. For devices that only support on or off lights, everything that's not off will turn
+ * the light on. If the light is monochrome and only the brightness can be controlled, the RGB color
+ * will be converted to only a brightness value and that will be used for the light's single
+ * channel.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class LightState implements Parcelable {
+ private final int mColor;
+
+ /**
+ * Creates a new LightState with the desired color and intensity.
+ *
+ * @param color the desired color and intensity in ARGB format.
+ */
+ public LightState(@ColorInt int color) {
+ mColor = color;
+ }
+
+ private LightState(@NonNull Parcel in) {
+ mColor = in.readInt();
+ }
+
+ /**
+ * Return the color and intensity associated with this LightState.
+ * @return the color and intensity in ARGB format. The A channel is ignored.
+ */
+ public @ColorInt int getColor() {
+ return mColor;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<LightState> CREATOR =
+ new Parcelable.Creator<LightState>() {
+ public LightState createFromParcel(Parcel in) {
+ return new LightState(in);
+ }
+
+ public LightState[] newArray(int size) {
+ return new LightState[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
new file mode 100644
index 000000000000..1bc051b977a8
--- /dev/null
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.CloseGuard;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.Reference;
+import java.util.List;
+
+/**
+ * The LightsManager class allows control over device lights.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+@SystemService(Context.LIGHTS_SERVICE)
+public final class LightsManager {
+ private static final String TAG = "LightsManager";
+
+ // These enum values copy the values from {@link com.android.server.lights.LightsManager}
+ // and the light HAL. Since 0-7 are lights reserved for system use, only the microphone light
+ // is available through this API.
+ /** Type for lights that indicate microphone usage */
+ public static final int LIGHT_TYPE_MICROPHONE = 8;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"LIGHT_TYPE_"},
+ value = {
+ LIGHT_TYPE_MICROPHONE,
+ })
+ public @interface LightType {}
+
+ @NonNull private final Context mContext;
+ @NonNull private final ILightsManager mService;
+
+ /**
+ * Creates a LightsManager.
+ *
+ * @hide
+ */
+ public LightsManager(@NonNull Context context) throws ServiceNotFoundException {
+ this(context, ILightsManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.LIGHTS_SERVICE)));
+ }
+
+ /**
+ * Creates a LightsManager with a provided service implementation.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public LightsManager(@NonNull Context context, @NonNull ILightsManager service) {
+ mContext = Preconditions.checkNotNull(context);
+ mService = Preconditions.checkNotNull(service);
+ }
+
+ /**
+ * Returns the lights available on the device.
+ *
+ * @return A list of available lights
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ public @NonNull List<Light> getLights() {
+ try {
+ return mService.getLights();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the state of a specified light.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @TestApi
+ public @NonNull LightState getLightState(@NonNull Light light) {
+ Preconditions.checkNotNull(light);
+ try {
+ return mService.getLightState(light.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a new LightsSession that can be used to control the device lights.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ public @NonNull LightsSession openSession() {
+ try {
+ final LightsSession session = new LightsSession();
+ mService.openSession(session.mToken);
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Encapsulates a session that can be used to control device lights and represents the lifetime
+ * of the requests.
+ */
+ public final class LightsSession implements AutoCloseable {
+
+ private final IBinder mToken = new Binder();
+
+ private final CloseGuard mCloseGuard = new CloseGuard();
+ private boolean mClosed = false;
+
+ /**
+ * Instantiated by {@link LightsManager#openSession()}.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ private LightsSession() {
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Sends a request to modify the states of multiple lights.
+ *
+ * <p>This method only controls lights that aren't overridden by higher-priority sessions.
+ * Additionally, lights not controlled by this session can be controlled by lower-priority
+ * sessions.
+ *
+ * @param request the settings for lights that should change
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ public void setLights(@NonNull LightsRequest request) {
+ Preconditions.checkNotNull(request);
+ if (!mClosed) {
+ try {
+ mService.setLightStates(mToken, request.mLightIds, request.mLightStates);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Closes the session, reverting all changes made through it.
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
+ @Override
+ public void close() {
+ if (!mClosed) {
+ try {
+ mService.closeSession(mToken);
+ mClosed = true;
+ mCloseGuard.close();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ Reference.reachabilityFence(this);
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+}
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
new file mode 100644
index 000000000000..a36da4c7d85d
--- /dev/null
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.lights;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.util.SparseArray;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Encapsulates a request to modify the state of multiple lights.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class LightsRequest {
+
+ /** Visible to {@link LightsManager.Session}. */
+ final int[] mLightIds;
+
+ /** Visible to {@link LightsManager.Session}. */
+ final LightState[] mLightStates;
+
+ /**
+ * Can only be constructed via {@link LightsRequest.Builder#build()}.
+ */
+ private LightsRequest(SparseArray<LightState> changes) {
+ final int n = changes.size();
+ mLightIds = new int[n];
+ mLightStates = new LightState[n];
+ for (int i = 0; i < n; i++) {
+ mLightIds[i] = changes.keyAt(i);
+ mLightStates[i] = changes.valueAt(i);
+ }
+ }
+
+ /**
+ * Builder for creating device light change requests.
+ */
+ public static final class Builder {
+
+ private final SparseArray<LightState> mChanges = new SparseArray<>();
+
+ /**
+ * Overrides the color and intensity of a given light.
+ *
+ * @param light the light to modify
+ * @param state the desired color and intensity of the light
+ */
+ public @NonNull Builder setLight(@NonNull Light light, @NonNull LightState state) {
+ Preconditions.checkNotNull(light);
+ Preconditions.checkNotNull(state);
+ mChanges.put(light.getId(), state);
+ return this;
+ }
+
+ /**
+ * Removes the override for the color and intensity of a given light.
+ *
+ * @param light the light to modify
+ */
+ public @NonNull Builder clearLight(@NonNull Light light) {
+ Preconditions.checkNotNull(light);
+ mChanges.put(light.getId(), null);
+ return this;
+ }
+
+ /**
+ * Create a LightsRequest object used to override lights on the device.
+ *
+ * <p>The generated {@link LightsRequest} should be used in
+ * {@link LightsManager.Session#setLights(LightsLightsRequest).
+ */
+ public @NonNull LightsRequest build() {
+ return new LightsRequest(mChanges);
+ }
+ }
+}
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index a11f2e9e8373..6d56d2d45922 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -21,6 +21,7 @@ import android.annotation.SystemApi;
import android.hardware.contexthub.V1_0.ContextHub;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
@@ -270,6 +271,30 @@ public class ContextHubInfo implements Parcelable {
return retVal;
}
+ /**
+ * Dump the internal state as a ContextHubInfoProto to the given ProtoOutputStream.
+ *
+ * If the output belongs to a sub message, the caller is responsible for wrapping this function
+ * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
+ *
+ * @hide
+ */
+ public void dump(ProtoOutputStream proto) {
+ proto.write(ContextHubInfoProto.ID, mId);
+ proto.write(ContextHubInfoProto.NAME, mName);
+ proto.write(ContextHubInfoProto.VENDOR, mVendor);
+ proto.write(ContextHubInfoProto.TOOLCHAIN, mToolchain);
+ proto.write(ContextHubInfoProto.PLATFORM_VERSION, mPlatformVersion);
+ proto.write(ContextHubInfoProto.STATIC_SW_VERSION, getStaticSwVersion());
+ proto.write(ContextHubInfoProto.TOOLCHAIN_VERSION, mToolchainVersion);
+ proto.write(ContextHubInfoProto.CHRE_PLATFORM_ID, mChrePlatformId);
+ proto.write(ContextHubInfoProto.PEAK_MIPS, mPeakMips);
+ proto.write(ContextHubInfoProto.STOPPED_POWER_DRAW_MW, mStoppedPowerDrawMw);
+ proto.write(ContextHubInfoProto.SLEEP_POWER_DRAW_MW, mSleepPowerDrawMw);
+ proto.write(ContextHubInfoProto.PEAK_POWER_DRAW_MW, mPeakPowerDrawMw);
+ proto.write(ContextHubInfoProto.MAX_PACKET_LENGTH_BYTES, mMaxPacketLengthBytes);
+ }
+
@Override
public boolean equals(@Nullable Object object) {
if (object == this) {
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index d43a619a7c1f..a30fd6b51e76 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -130,7 +130,7 @@ class ConversionUtil {
aidlPhrase.id = apiPhrase.id;
aidlPhrase.recognitionModes = api2aidlRecognitionModes(apiPhrase.recognitionModes);
aidlPhrase.users = Arrays.copyOf(apiPhrase.users, apiPhrase.users.length);
- aidlPhrase.locale = apiPhrase.locale;
+ aidlPhrase.locale = apiPhrase.locale.toLanguageTag();
aidlPhrase.text = apiPhrase.text;
return aidlPhrase;
}
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index eb5d0cb539a1..ef76c620f3f3 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -17,6 +17,7 @@
package android.hardware.soundtrigger;
import android.Manifest;
+import android.annotation.IntDef;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -24,7 +25,6 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.service.voice.AlwaysOnHotwordDetector;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -35,6 +35,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -66,9 +68,10 @@ public class KeyphraseEnrollmentInfo {
"com.android.intent.action.MANAGE_VOICE_KEYPHRASES";
/**
* Intent extra: The intent extra for the specific manage action that needs to be performed.
- * Possible values are {@link AlwaysOnHotwordDetector#MANAGE_ACTION_ENROLL},
- * {@link AlwaysOnHotwordDetector#MANAGE_ACTION_RE_ENROLL}
- * or {@link AlwaysOnHotwordDetector#MANAGE_ACTION_UN_ENROLL}.
+ *
+ * @see #MANAGE_ACTION_ENROLL
+ * @see #MANAGE_ACTION_RE_ENROLL
+ * @see #MANAGE_ACTION_UN_ENROLL
*/
public static final String EXTRA_VOICE_KEYPHRASE_ACTION =
"com.android.intent.extra.VOICE_KEYPHRASE_ACTION";
@@ -86,6 +89,31 @@ public class KeyphraseEnrollmentInfo {
"com.android.intent.extra.VOICE_KEYPHRASE_LOCALE";
/**
+ * Keyphrase management actions used with the {@link #EXTRA_VOICE_KEYPHRASE_ACTION} intent extra
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "MANAGE_ACTION_" }, value = {
+ MANAGE_ACTION_ENROLL,
+ MANAGE_ACTION_RE_ENROLL,
+ MANAGE_ACTION_UN_ENROLL
+ })
+ public @interface ManageActions {}
+
+ /**
+ * Indicates desired action to enroll keyphrase model
+ */
+ public static final int MANAGE_ACTION_ENROLL = 0;
+ /**
+ * Indicates desired action to re-enroll keyphrase model
+ */
+ public static final int MANAGE_ACTION_RE_ENROLL = 1;
+ /**
+ * Indicates desired action to un-enroll keyphrase model
+ */
+ public static final int MANAGE_ACTION_UN_ENROLL = 2;
+
+ /**
* List of available keyphrases.
*/
final private KeyphraseMetadata[] mKeyphrases;
@@ -294,15 +322,13 @@ public class KeyphraseEnrollmentInfo {
* for the locale.
*
* @param action The enrollment related action that this intent is supposed to perform.
- * This can be one of {@link AlwaysOnHotwordDetector#MANAGE_ACTION_ENROLL},
- * {@link AlwaysOnHotwordDetector#MANAGE_ACTION_RE_ENROLL}
- * or {@link AlwaysOnHotwordDetector#MANAGE_ACTION_UN_ENROLL}
* @param keyphrase The keyphrase that the user needs to be enrolled to.
* @param locale The locale for which the enrollment needs to be performed.
* @return An {@link Intent} to manage the keyphrase. This can be null if managing the
* given keyphrase/locale combination isn't possible.
*/
- public Intent getManageKeyphraseIntent(int action, String keyphrase, Locale locale) {
+ public Intent getManageKeyphraseIntent(@ManageActions int action, String keyphrase,
+ Locale locale) {
if (mKeyphrasePackageMap == null || mKeyphrasePackageMap.isEmpty()) {
Slog.w(TAG, "No enrollment application exists");
return null;
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseMetadata.aidl b/core/java/android/hardware/soundtrigger/KeyphraseMetadata.aidl
new file mode 100644
index 000000000000..7a5e932bb7a0
--- /dev/null
+++ b/core/java/android/hardware/soundtrigger/KeyphraseMetadata.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger;
+
+parcelable KeyphraseMetadata;
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java b/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java
index ed8c296e572f..15462deea158 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java
@@ -16,8 +16,13 @@
package android.hardware.soundtrigger;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
import android.util.ArraySet;
+import com.android.internal.util.DataClass;
+
import java.util.Locale;
/**
@@ -25,37 +30,168 @@ import java.util.Locale;
*
* @hide
*/
-public class KeyphraseMetadata {
+@DataClass(
+ genEqualsHashCode = true,
+ genToString = true,
+ genConstructor = false,
+ genHiddenConstDefs = true)
+public final class KeyphraseMetadata implements Parcelable {
public final int id;
+ @NonNull
public final String keyphrase;
+ @NonNull
public final ArraySet<Locale> supportedLocales;
public final int recognitionModeFlags;
- public KeyphraseMetadata(int id, String keyphrase, ArraySet<Locale> supportedLocales,
- int recognitionModeFlags) {
+ public KeyphraseMetadata(int id, @NonNull String keyphrase,
+ @NonNull ArraySet<Locale> supportedLocales, int recognitionModeFlags) {
this.id = id;
this.keyphrase = keyphrase;
this.supportedLocales = supportedLocales;
this.recognitionModeFlags = recognitionModeFlags;
}
- @Override
- public String toString() {
- return "id=" + id + ", keyphrase=" + keyphrase + ", supported-locales=" + supportedLocales
- + ", recognition-modes=" + recognitionModeFlags;
- }
-
/**
* @return Indicates if we support the given phrase.
*/
- public boolean supportsPhrase(String phrase) {
+ public boolean supportsPhrase(@Nullable String phrase) {
return keyphrase.isEmpty() || keyphrase.equalsIgnoreCase(phrase);
}
/**
* @return Indicates if we support the given locale.
*/
- public boolean supportsLocale(Locale locale) {
+ public boolean supportsLocale(@Nullable Locale locale) {
return supportedLocales.isEmpty() || supportedLocales.contains(locale);
}
+
+
+
+
+ // Code below generated by codegen v1.0.14.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "KeyphraseMetadata { " +
+ "id = " + id + ", " +
+ "keyphrase = " + keyphrase + ", " +
+ "supportedLocales = " + supportedLocales + ", " +
+ "recognitionModeFlags = " + recognitionModeFlags +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(KeyphraseMetadata other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ KeyphraseMetadata that = (KeyphraseMetadata) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && id == that.id
+ && java.util.Objects.equals(keyphrase, that.keyphrase)
+ && java.util.Objects.equals(supportedLocales, that.supportedLocales)
+ && recognitionModeFlags == that.recognitionModeFlags;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + id;
+ _hash = 31 * _hash + java.util.Objects.hashCode(keyphrase);
+ _hash = 31 * _hash + java.util.Objects.hashCode(supportedLocales);
+ _hash = 31 * _hash + recognitionModeFlags;
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(id);
+ dest.writeString(keyphrase);
+ dest.writeArraySet(supportedLocales);
+ dest.writeInt(recognitionModeFlags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ KeyphraseMetadata(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int _id = in.readInt();
+ String _keyphrase = in.readString();
+ ArraySet<Locale> _supportedLocales = (ArraySet) in.readArraySet(null);
+ int _recognitionModeFlags = in.readInt();
+
+ this.id = _id;
+ this.keyphrase = _keyphrase;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, keyphrase);
+ this.supportedLocales = _supportedLocales;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, supportedLocales);
+ this.recognitionModeFlags = _recognitionModeFlags;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<KeyphraseMetadata> CREATOR
+ = new Parcelable.Creator<KeyphraseMetadata>() {
+ @Override
+ public KeyphraseMetadata[] newArray(int size) {
+ return new KeyphraseMetadata[size];
+ }
+
+ @Override
+ public KeyphraseMetadata createFromParcel(@NonNull android.os.Parcel in) {
+ return new KeyphraseMetadata(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1579290593964L,
+ codegenVersion = "1.0.14",
+ sourceFile = "frameworks/base/core/java/android/hardware/soundtrigger/KeyphraseMetadata.java",
+ inputSignatures = "public final int id\npublic final @android.annotation.NonNull java.lang.String keyphrase\npublic final @android.annotation.NonNull android.util.ArraySet<java.util.Locale> supportedLocales\npublic final int recognitionModeFlags\npublic boolean supportsPhrase(java.lang.String)\npublic boolean supportsLocale(java.util.Locale)\nclass KeyphraseMetadata extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genConstructor=false, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 1932f46975c5..d505ae59dfaf 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -49,6 +49,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Locale;
import java.util.UUID;
/**
@@ -148,6 +149,7 @@ public class SoundTrigger {
public final int maxUsers;
/** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */
+ @RecognitionModes
public final int recognitionModes;
/** Supports seamless transition to capture mode after recognition */
@@ -175,9 +177,9 @@ public class SoundTrigger {
ModuleProperties(int id, @NonNull String implementor, @NonNull String description,
@NonNull String uuid, int version, @NonNull String supportedModelArch,
- int maxSoundModels, int maxKeyphrases, int maxUsers, int recognitionModes,
- boolean supportsCaptureTransition, int maxBufferMs,
- boolean supportsConcurrentCapture, int powerConsumptionMw,
+ int maxSoundModels, int maxKeyphrases, int maxUsers,
+ @RecognitionModes int recognitionModes, boolean supportsCaptureTransition,
+ int maxBufferMs, boolean supportsConcurrentCapture, int powerConsumptionMw,
boolean returnsTriggerInEvent, int audioCapabilities) {
this.id = id;
this.implementor = requireNonNull(implementor);
@@ -271,16 +273,27 @@ public class SoundTrigger {
}
}
- /*****************************************************************************
+ /**
* A SoundModel describes the attributes and contains the binary data used by the hardware
* implementation to detect a particular sound pattern.
* A specialized version {@link KeyphraseSoundModel} is defined for key phrase
* sound models.
- *
- * @hide
- ****************************************************************************/
+ */
public static class SoundModel {
- /** Undefined sound model type */
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_GENERIC_SOUND,
+ TYPE_KEYPHRASE,
+ TYPE_UNKNOWN,
+ })
+ public @interface SoundModelType {}
+
+ /**
+ * Undefined sound model type
+ * @hide
+ */
public static final int TYPE_UNKNOWN = -1;
/** Keyphrase sound model */
@@ -293,15 +306,14 @@ public class SoundTrigger {
public static final int TYPE_GENERIC_SOUND = 1;
/** Unique sound model identifier */
- @UnsupportedAppUsage
@NonNull
public final UUID uuid;
/** Sound model type (e.g. TYPE_KEYPHRASE); */
+ @SoundModelType
public final int type;
/** Unique sound model vendor identifier */
- @UnsupportedAppUsage
@NonNull
public final UUID vendorUuid;
@@ -309,11 +321,11 @@ public class SoundTrigger {
public final int version;
/** Opaque data. For use by vendor implementation and enrollment application */
- @UnsupportedAppUsage
@NonNull
public final byte[] data;
- public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, int type,
+ /** @hide */
+ public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, @SoundModelType int type,
@Nullable byte[] data, int version) {
this.uuid = requireNonNull(uuid);
this.vendorUuid = vendorUuid != null ? vendorUuid : new UUID(0, 0);
@@ -336,67 +348,90 @@ public class SoundTrigger {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (!(obj instanceof SoundModel))
+ }
+ if (!(obj instanceof SoundModel)) {
return false;
+ }
SoundModel other = (SoundModel) obj;
- if (type != other.type)
+ if (type != other.type) {
return false;
+ }
if (uuid == null) {
- if (other.uuid != null)
+ if (other.uuid != null) {
return false;
- } else if (!uuid.equals(other.uuid))
+ }
+ } else if (!uuid.equals(other.uuid)) {
return false;
+ }
if (vendorUuid == null) {
- if (other.vendorUuid != null)
+ if (other.vendorUuid != null) {
return false;
- } else if (!vendorUuid.equals(other.vendorUuid))
+ }
+ } else if (!vendorUuid.equals(other.vendorUuid)) {
return false;
- if (!Arrays.equals(data, other.data))
+ }
+ if (!Arrays.equals(data, other.data)) {
return false;
- if (version != other.version)
+ }
+ if (version != other.version) {
return false;
+ }
return true;
}
}
- /*****************************************************************************
+ /**
* A Keyphrase describes a key phrase that can be detected by a
* {@link KeyphraseSoundModel}
- *
- * @hide
- ****************************************************************************/
- public static class Keyphrase implements Parcelable {
+ */
+ public static final class Keyphrase implements Parcelable {
/** Unique identifier for this keyphrase */
- @UnsupportedAppUsage
public final int id;
- /** Recognition modes supported for this key phrase in the model */
- @UnsupportedAppUsage
+ /**
+ * Recognition modes supported for this key phrase in the model
+ *
+ * @see #RECOGNITION_MODE_VOICE_TRIGGER
+ * @see #RECOGNITION_MODE_USER_IDENTIFICATION
+ * @see #RECOGNITION_MODE_USER_AUTHENTICATION
+ * @see #RECOGNITION_MODE_GENERIC
+ */
+ @RecognitionModes
public final int recognitionModes;
- /** Locale of the keyphrase. JAVA Locale string e.g en_US */
- @UnsupportedAppUsage
+ /** Locale of the keyphrase. */
@NonNull
- public final String locale;
+ public final Locale locale;
/** Key phrase text */
- @UnsupportedAppUsage
@NonNull
public final String text;
- /** Users this key phrase has been trained for. countains sound trigger specific user IDs
- * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}. */
- @UnsupportedAppUsage
+ /**
+ * Users this key phrase has been trained for. countains sound trigger specific user IDs
+ * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}.
+ */
@NonNull
public final int[] users;
- @UnsupportedAppUsage
- public Keyphrase(int id, int recognitionModes, @NonNull String locale, @NonNull String text,
- @Nullable int[] users) {
+ /**
+ * Constructor for Keyphrase describes a key phrase that can be detected by a
+ * {@link KeyphraseSoundModel}
+ *
+ * @param id Unique keyphrase identifier for this keyphrase
+ * @param recognitionModes Bit field representation of recognition modes this keyphrase
+ * supports
+ * @param locale Locale of the keyphrase
+ * @param text Key phrase text
+ * @param users Users this key phrase has been trained for.
+ */
+ public Keyphrase(int id, @RecognitionModes int recognitionModes, @NonNull Locale locale,
+ @NonNull String text, @Nullable int[] users) {
this.id = id;
this.recognitionModes = recognitionModes;
this.locale = requireNonNull(locale);
@@ -404,21 +439,27 @@ public class SoundTrigger {
this.users = users != null ? users : new int[0];
}
- public static final @android.annotation.NonNull Parcelable.Creator<Keyphrase> CREATOR
- = new Parcelable.Creator<Keyphrase>() {
- public Keyphrase createFromParcel(Parcel in) {
- return Keyphrase.fromParcel(in);
+ public static final @NonNull Parcelable.Creator<Keyphrase> CREATOR =
+ new Parcelable.Creator<Keyphrase>() {
+ @NonNull
+ public Keyphrase createFromParcel(@NonNull Parcel in) {
+ return Keyphrase.readFromParcel(in);
}
+ @NonNull
public Keyphrase[] newArray(int size) {
return new Keyphrase[size];
}
};
- private static Keyphrase fromParcel(Parcel in) {
+ /**
+ * Read from Parcel to generate keyphrase
+ */
+ @NonNull
+ public static Keyphrase readFromParcel(@NonNull Parcel in) {
int id = in.readInt();
int recognitionModes = in.readInt();
- String locale = in.readString();
+ Locale locale = Locale.forLanguageTag(in.readString());
String text = in.readString();
int[] users = null;
int numUsers = in.readInt();
@@ -430,10 +471,10 @@ public class SoundTrigger {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(recognitionModes);
- dest.writeString(locale);
+ dest.writeString(locale.toLanguageTag());
dest.writeString(text);
if (users != null) {
dest.writeInt(users.length);
@@ -443,6 +484,7 @@ public class SoundTrigger {
}
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
@@ -462,49 +504,57 @@ public class SoundTrigger {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
Keyphrase other = (Keyphrase) obj;
if (text == null) {
- if (other.text != null)
+ if (other.text != null) {
return false;
- } else if (!text.equals(other.text))
+ }
+ } else if (!text.equals(other.text)) {
return false;
- if (id != other.id)
+ }
+ if (id != other.id) {
return false;
+ }
if (locale == null) {
- if (other.locale != null)
+ if (other.locale != null) {
return false;
- } else if (!locale.equals(other.locale))
+ }
+ } else if (!locale.equals(other.locale)) {
return false;
- if (recognitionModes != other.recognitionModes)
+ }
+ if (recognitionModes != other.recognitionModes) {
return false;
- if (!Arrays.equals(users, other.users))
+ }
+ if (!Arrays.equals(users, other.users)) {
return false;
+ }
return true;
}
@Override
public String toString() {
- return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes + ", locale="
- + locale + ", text=" + text + ", users=" + Arrays.toString(users) + "]";
+ return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes
+ + ", locale=" + locale.toLanguageTag() + ", text=" + text
+ + ", users=" + Arrays.toString(users) + "]";
}
}
- /*****************************************************************************
+ /**
* A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases.
* It contains data needed by the hardware to detect a certain number of key phrases
* and the list of corresponding {@link Keyphrase} descriptors.
- *
- * @hide
- ****************************************************************************/
- public static class KeyphraseSoundModel extends SoundModel implements Parcelable {
+ */
+ public static final class KeyphraseSoundModel extends SoundModel implements Parcelable {
/** Key phrases in this sound model */
- @UnsupportedAppUsage
@NonNull
public final Keyphrase[] keyphrases; // keyword phrases in model
@@ -515,24 +565,29 @@ public class SoundTrigger {
this.keyphrases = keyphrases != null ? keyphrases : new Keyphrase[0];
}
- @UnsupportedAppUsage
public KeyphraseSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
@Nullable byte[] data, @Nullable Keyphrase[] keyphrases) {
this(uuid, vendorUuid, data, keyphrases, -1);
}
- public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR
- = new Parcelable.Creator<KeyphraseSoundModel>() {
- public KeyphraseSoundModel createFromParcel(Parcel in) {
- return KeyphraseSoundModel.fromParcel(in);
+ public static final @NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR =
+ new Parcelable.Creator<KeyphraseSoundModel>() {
+ @NonNull
+ public KeyphraseSoundModel createFromParcel(@NonNull Parcel in) {
+ return KeyphraseSoundModel.readFromParcel(in);
}
+ @NonNull
public KeyphraseSoundModel[] newArray(int size) {
return new KeyphraseSoundModel[size];
}
};
- private static KeyphraseSoundModel fromParcel(Parcel in) {
+ /**
+ * Read from Parcel to generate KeyphraseSoundModel
+ */
+ @NonNull
+ public static KeyphraseSoundModel readFromParcel(@NonNull Parcel in) {
UUID uuid = UUID.fromString(in.readString());
UUID vendorUuid = null;
int length = in.readInt();
@@ -545,13 +600,14 @@ public class SoundTrigger {
return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases, version);
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(uuid.toString());
if (vendorUuid == null) {
dest.writeInt(-1);
@@ -583,15 +639,19 @@ public class SoundTrigger {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (!super.equals(obj))
+ }
+ if (!super.equals(obj)) {
return false;
- if (!(obj instanceof KeyphraseSoundModel))
+ }
+ if (!(obj instanceof KeyphraseSoundModel)) {
return false;
+ }
KeyphraseSoundModel other = (KeyphraseSoundModel) obj;
- if (!Arrays.equals(keyphrases, other.keyphrases))
+ if (!Arrays.equals(keyphrases, other.keyphrases)) {
return false;
+ }
return true;
}
}
@@ -760,31 +820,32 @@ public class SoundTrigger {
}
/**
- * Modes for key phrase recognition
+ * Modes for key phrase recognition
+ * @hide
*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "RECOGNITION_MODE_" }, value = {
+ RECOGNITION_MODE_VOICE_TRIGGER,
+ RECOGNITION_MODE_USER_IDENTIFICATION,
+ RECOGNITION_MODE_USER_AUTHENTICATION,
+ RECOGNITION_MODE_GENERIC
+ })
+ public @interface RecognitionModes {}
/**
- * Simple recognition of the key phrase
- *
- * @hide
+ * Trigger on recognition of a key phrase
*/
public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1;
/**
* Trigger only if one user is identified
- *
- * @hide
*/
public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2;
/**
* Trigger only if one user is authenticated
- *
- * @hide
*/
public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4;
/**
* Generic (non-speech) recognition.
- *
- * @hide
*/
public static final int RECOGNITION_MODE_GENERIC = 0x8;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 81a0d629380a..92047dcad09e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -20,8 +20,8 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -1240,16 +1240,16 @@ public class InputMethodService extends AbstractInputMethodService {
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
- mWindow.getWindow().setFitWindowInsetsTypes(WindowInsets.Type.systemBars());
- mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND);
+ mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars());
+
+ // IME layout should always be inset by navigation bar, no matter it's current visibility.
mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> v.onApplyWindowInsets(
- new WindowInsets.Builder(insets).setSystemWindowInsets(
- android.graphics.Insets.of(
- insets.getSystemWindowInsetLeft(),
- insets.getSystemWindowInsetTop(),
- insets.getSystemWindowInsetRight(),
- insets.getStableInsetBottom())).build()));
+ new WindowInsets.Builder(insets).setInsets(
+ navigationBars(),
+ insets.getInsetsIgnoringVisibility(navigationBars()))
+ .build()));
+
// For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
// by default (but IME developers can opt this out later if they want a new behavior).
mWindow.getWindow().setFlags(
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
new file mode 100644
index 000000000000..82ba0ca113c5
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
+parcelable ConnectivityDiagnosticsManager.DataStallReport; \ No newline at end of file
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 6afdb5ef1b16..a6f9b96269e1 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -18,10 +18,18 @@ package android.net;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -47,38 +55,47 @@ import java.util.concurrent.Executor;
* </ul>
*/
public class ConnectivityDiagnosticsManager {
- public static final int DETECTION_METHOD_DNS_EVENTS = 1;
- public static final int DETECTION_METHOD_TCP_METRICS = 2;
+ private final Context mContext;
+ private final IConnectivityManager mService;
/** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = {"DETECTION_METHOD_"},
- value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
- public @interface DetectionMethod {}
+ public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
+ mContext = Preconditions.checkNotNull(context, "missing context");
+ mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ }
/** @hide */
- public ConnectivityDiagnosticsManager() {}
+ @VisibleForTesting
+ public static boolean persistableBundleEquals(
+ @Nullable PersistableBundle a, @Nullable PersistableBundle b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+ if (!Objects.equals(a.keySet(), b.keySet())) return false;
+ for (String key : a.keySet()) {
+ if (!Objects.equals(a.get(key), b.get(key))) return false;
+ }
+ return true;
+ }
/** Class that includes connectivity information for a specific Network at a specific time. */
- public static class ConnectivityReport {
+ public static final class ConnectivityReport implements Parcelable {
/** The Network for which this ConnectivityReport applied */
- @NonNull public final Network network;
+ @NonNull private final Network mNetwork;
/**
* The timestamp for the report. The timestamp is taken from {@link
* System#currentTimeMillis}.
*/
- public final long reportTimestamp;
+ private final long mReportTimestamp;
/** LinkProperties available on the Network at the reported timestamp */
- @NonNull public final LinkProperties linkProperties;
+ @NonNull private final LinkProperties mLinkProperties;
/** NetworkCapabilities available on the Network at the reported timestamp */
- @NonNull public final NetworkCapabilities networkCapabilities;
+ @NonNull private final NetworkCapabilities mNetworkCapabilities;
/** PersistableBundle that may contain additional info about the report */
- @NonNull public final PersistableBundle additionalInfo;
+ @NonNull private final PersistableBundle mAdditionalInfo;
/**
* Constructor for ConnectivityReport.
@@ -101,30 +118,148 @@ public class ConnectivityDiagnosticsManager {
@NonNull LinkProperties linkProperties,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull PersistableBundle additionalInfo) {
- this.network = network;
- this.reportTimestamp = reportTimestamp;
- this.linkProperties = linkProperties;
- this.networkCapabilities = networkCapabilities;
- this.additionalInfo = additionalInfo;
+ mNetwork = network;
+ mReportTimestamp = reportTimestamp;
+ mLinkProperties = linkProperties;
+ mNetworkCapabilities = networkCapabilities;
+ mAdditionalInfo = additionalInfo;
+ }
+
+ /**
+ * Returns the Network for this ConnectivityReport.
+ *
+ * @return The Network for which this ConnectivityReport applied
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * Returns the epoch timestamp (milliseconds) for when this report was taken.
+ *
+ * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+ */
+ public long getReportTimestamp() {
+ return mReportTimestamp;
+ }
+
+ /**
+ * Returns the LinkProperties available when this report was taken.
+ *
+ * @return LinkProperties available on the Network at the reported timestamp
+ */
+ @NonNull
+ public LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
}
+
+ /**
+ * Returns the NetworkCapabilities when this report was taken.
+ *
+ * @return NetworkCapabilities available on the Network at the reported timestamp
+ */
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return new NetworkCapabilities(mNetworkCapabilities);
+ }
+
+ /**
+ * Returns a PersistableBundle with additional info for this report.
+ *
+ * @return PersistableBundle that may contain additional info about the report
+ */
+ @NonNull
+ public PersistableBundle getAdditionalInfo() {
+ return new PersistableBundle(mAdditionalInfo);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ConnectivityReport)) return false;
+ final ConnectivityReport that = (ConnectivityReport) o;
+
+ // PersistableBundle is optimized to avoid unparcelling data unless fields are
+ // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+ // {@link PersistableBundle#kindofEquals}.
+ return mReportTimestamp == that.mReportTimestamp
+ && mNetwork.equals(that.mNetwork)
+ && mLinkProperties.equals(that.mLinkProperties)
+ && mNetworkCapabilities.equals(that.mNetworkCapabilities)
+ && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mNetwork,
+ mReportTimestamp,
+ mLinkProperties,
+ mNetworkCapabilities,
+ mAdditionalInfo);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mNetwork, flags);
+ dest.writeLong(mReportTimestamp);
+ dest.writeParcelable(mLinkProperties, flags);
+ dest.writeParcelable(mNetworkCapabilities, flags);
+ dest.writeParcelable(mAdditionalInfo, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<ConnectivityReport> CREATOR =
+ new Creator<>() {
+ public ConnectivityReport createFromParcel(Parcel in) {
+ return new ConnectivityReport(
+ in.readParcelable(null),
+ in.readLong(),
+ in.readParcelable(null),
+ in.readParcelable(null),
+ in.readParcelable(null));
+ }
+
+ public ConnectivityReport[] newArray(int size) {
+ return new ConnectivityReport[size];
+ }
+ };
}
/** Class that includes information for a suspected data stall on a specific Network */
- public static class DataStallReport {
+ public static final class DataStallReport implements Parcelable {
+ 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 {}
+
/** The Network for which this DataStallReport applied */
- @NonNull public final Network network;
+ @NonNull private final Network mNetwork;
/**
* The timestamp for the report. The timestamp is taken from {@link
* System#currentTimeMillis}.
*/
- public final long reportTimestamp;
+ private long mReportTimestamp;
/** The detection method used to identify the suspected data stall */
- @DetectionMethod public final int detectionMethod;
+ @DetectionMethod private final int mDetectionMethod;
/** PersistableBundle that may contain additional information on the suspected data stall */
- @NonNull public final PersistableBundle stallDetails;
+ @NonNull private final PersistableBundle mStallDetails;
/**
* Constructor for DataStallReport.
@@ -143,11 +278,101 @@ public class ConnectivityDiagnosticsManager {
long reportTimestamp,
@DetectionMethod int detectionMethod,
@NonNull PersistableBundle stallDetails) {
- this.network = network;
- this.reportTimestamp = reportTimestamp;
- this.detectionMethod = detectionMethod;
- this.stallDetails = stallDetails;
+ mNetwork = network;
+ mReportTimestamp = reportTimestamp;
+ mDetectionMethod = detectionMethod;
+ mStallDetails = stallDetails;
+ }
+
+ /**
+ * Returns the Network for this DataStallReport.
+ *
+ * @return The Network for which this DataStallReport applied
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * Returns the epoch timestamp (milliseconds) for when this report was taken.
+ *
+ * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+ */
+ public long getReportTimestamp() {
+ return mReportTimestamp;
+ }
+
+ /**
+ * Returns the detection method used to identify this suspected data stall.
+ *
+ * @return The detection method used to identify the suspected data stall
+ */
+ public int getDetectionMethod() {
+ return mDetectionMethod;
+ }
+
+ /**
+ * Returns a PersistableBundle with additional info for this report.
+ *
+ * @return PersistableBundle that may contain additional information on the suspected data
+ * stall
+ */
+ @NonNull
+ public PersistableBundle getStallDetails() {
+ return new PersistableBundle(mStallDetails);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DataStallReport)) return false;
+ final DataStallReport that = (DataStallReport) o;
+
+ // PersistableBundle is optimized to avoid unparcelling data unless fields are
+ // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+ // {@link PersistableBundle#kindofEquals}.
+ return mReportTimestamp == that.mReportTimestamp
+ && mDetectionMethod == that.mDetectionMethod
+ && mNetwork.equals(that.mNetwork)
+ && persistableBundleEquals(mStallDetails, that.mStallDetails);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetwork, mReportTimestamp, mDetectionMethod, mStallDetails);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mNetwork, flags);
+ dest.writeLong(mReportTimestamp);
+ dest.writeInt(mDetectionMethod);
+ dest.writeParcelable(mStallDetails, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<DataStallReport> CREATOR =
+ new Creator<DataStallReport>() {
+ public DataStallReport createFromParcel(Parcel in) {
+ return new DataStallReport(
+ in.readParcelable(null),
+ in.readLong(),
+ in.readInt(),
+ in.readParcelable(null));
+ }
+
+ public DataStallReport[] newArray(int size) {
+ return new DataStallReport[size];
+ }
+ };
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8ba3131a83f1..ce9693d88a97 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -33,6 +33,9 @@ import android.content.Context;
import android.content.Intent;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.SocketKeepalive.Callback;
+import android.net.TetheringManager.StartTetheringCallback;
+import android.net.TetheringManager.TetheringEventCallback;
+import android.net.TetheringManager.TetheringRequest;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -58,6 +61,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
@@ -75,6 +79,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -484,34 +489,35 @@ public class ConnectivityManager {
* enable if any.
* @hide
*/
- public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE;
+ public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.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 = TetheringManager.EXTRA_REM_TETHER_TYPE;
+ public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.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 = TetheringManager.EXTRA_SET_ALARM;
+ public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM;
/**
* Tells the TetherService to run a provision check now.
* @hide
*/
- public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION;
+ public static final String EXTRA_RUN_PROVISION = TetheringConstants.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 = TetheringManager.EXTRA_PROVISION_CALLBACK;
+ public static final String EXTRA_PROVISION_CALLBACK =
+ TetheringConstants.EXTRA_PROVISION_CALLBACK;
/**
* The absence of a connection type.
@@ -2368,10 +2374,12 @@ public class ConnectivityManager {
*
* @return an array of 0 or more Strings of tetherable interface names.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableIfaces() {
return getTetheringManager().getTetherableIfaces();
}
@@ -2381,10 +2389,12 @@ public class ConnectivityManager {
*
* @return an array of 0 or more String of currently tethered interface names.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetheredIfaces() {
return getTetheringManager().getTetheredIfaces();
}
@@ -2400,10 +2410,12 @@ public class ConnectivityManager {
* @return an array of 0 or more String indicating the interface names
* which failed to tether.
*
+ * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetheringErroredIfaces() {
return getTetheringManager().getTetheringErroredIfaces();
}
@@ -2412,9 +2424,11 @@ public class ConnectivityManager {
* Get the set of tethered dhcp ranges.
*
* @return an array of 0 or more {@code String} of tethered dhcp ranges.
+ * @deprecated This API just return the default value which is not used in DhcpServer.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @Deprecated
public String[] getTetheredDhcpRanges() {
return getTetheringManager().getTetheredDhcpRanges();
}
@@ -2440,10 +2454,12 @@ public class ConnectivityManager {
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ * @deprecated Use {@link TetheringManager#startTethering} instead
*
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int tether(String iface) {
return getTetheringManager().tether(iface);
}
@@ -2467,6 +2483,7 @@ public class ConnectivityManager {
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int untether(String iface) {
return getTetheringManager().untether(iface);
}
@@ -2487,6 +2504,7 @@ public class ConnectivityManager {
*
* @return a boolean - {@code true} indicating Tethering is supported.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead.
* {@hide}
*/
@SystemApi
@@ -2498,9 +2516,12 @@ public class ConnectivityManager {
/**
* Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+ *
+ * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
public static abstract class OnStartTetheringCallback {
/**
* Called when tethering has been successfully started.
@@ -2517,9 +2538,12 @@ public class ConnectivityManager {
* Convenient overload for
* {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
* handler to run on the current thread's {@link Looper}.
+ *
+ * @deprecated Use {@link TetheringManager#startTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback) {
@@ -2543,26 +2567,44 @@ public class ConnectivityManager {
* @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
* of the result of trying to tether.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ *
+ * @deprecated Use {@link TetheringManager#startTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
- ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+ final Executor executor = new Executor() {
@Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- callback.onTetheringStarted();
+ public void execute(Runnable command) {
+ if (handler == null) {
+ command.run();
} else {
- callback.onTetheringFailed();
+ handler.post(command);
}
}
};
- getTetheringManager().startTethering(type, wrappedCallback, showProvisioningUi);
+ final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
+ @Override
+ public void onTetheringStarted() {
+ callback.onTetheringStarted();
+ }
+
+ @Override
+ public void onTetheringFailed(final int resultCode) {
+ callback.onTetheringFailed();
+ }
+ };
+
+ final TetheringRequest request = new TetheringRequest.Builder(type)
+ .setSilentProvisioning(!showProvisioningUi).build();
+
+ getTetheringManager().startTethering(request, executor, tetheringCallback);
}
/**
@@ -2573,9 +2615,12 @@ public class ConnectivityManager {
* {@link ConnectivityManager.TETHERING_WIFI},
* {@link ConnectivityManager.TETHERING_USB}, or
* {@link ConnectivityManager.TETHERING_BLUETOOTH}.
+ *
+ * @deprecated Use {@link TetheringManager#stopTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void stopTethering(int type) {
getTetheringManager().stopTethering(type);
@@ -2585,9 +2630,11 @@ public class ConnectivityManager {
* Callback for use with {@link registerTetheringEventCallback} to find out tethering
* upstream status.
*
- *@hide
+ * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead.
+ * @hide
*/
@SystemApi
+ @Deprecated
public abstract static class OnTetheringEventCallback {
/**
@@ -2600,6 +2647,10 @@ public class ConnectivityManager {
public void onUpstreamChanged(@Nullable Network network) {}
}
+ @GuardedBy("mTetheringEventCallbacks")
+ private final ArrayMap<OnTetheringEventCallback, TetheringEventCallback>
+ mTetheringEventCallbacks = new ArrayMap<>();
+
/**
* Start listening to tethering change events. Any new added callback will receive the last
* tethering status right away. If callback is registered when tethering has no upstream or
@@ -2608,16 +2659,30 @@ public class ConnectivityManager {
*
* @param executor the executor on which callback will be invoked.
* @param callback the callback to be called when tethering has change events.
+ *
+ * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void registerTetheringEventCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEventCallback callback) {
Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
- getTetheringManager().registerTetheringEventCallback(executor, callback);
+ final TetheringEventCallback tetherCallback =
+ new TetheringEventCallback() {
+ @Override
+ public void onUpstreamChanged(@Nullable Network network) {
+ callback.onUpstreamChanged(network);
+ }
+ };
+
+ synchronized (mTetheringEventCallbacks) {
+ mTetheringEventCallbacks.put(callback, tetherCallback);
+ getTetheringManager().registerTetheringEventCallback(executor, tetherCallback);
+ }
}
/**
@@ -2625,13 +2690,21 @@ public class ConnectivityManager {
* {@link #registerTetheringEventCallback}.
*
* @param callback previously registered callback.
+ *
+ * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void unregisterTetheringEventCallback(
@NonNull final OnTetheringEventCallback callback) {
- getTetheringManager().unregisterTetheringEventCallback(callback);
+ Objects.requireNonNull(callback, "The callback must be non-null");
+ synchronized (mTetheringEventCallbacks) {
+ final TetheringEventCallback tetherCallback =
+ mTetheringEventCallbacks.remove(callback);
+ getTetheringManager().unregisterTetheringEventCallback(tetherCallback);
+ }
}
@@ -2643,10 +2716,12 @@ public class ConnectivityManager {
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable usb interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableUsbRegexs() {
return getTetheringManager().getTetherableUsbRegexs();
}
@@ -2659,10 +2734,12 @@ public class ConnectivityManager {
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable wifi interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableWifiRegexs() {
return getTetheringManager().getTetherableWifiRegexs();
}
@@ -2675,10 +2752,13 @@ public class ConnectivityManager {
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable bluetooth interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged(
+ *TetheringManager.TetheringInterfaceRegexps)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableBluetoothRegexs() {
return getTetheringManager().getTetherableBluetoothRegexs();
}
@@ -2697,45 +2777,114 @@ public class ConnectivityManager {
*
* @param enable a boolean - {@code true} to enable tethering
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ * @deprecated Use {@link TetheringManager#startTethering} instead
*
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int setUsbTethering(boolean enable) {
return getTetheringManager().setUsbTethering(enable);
}
- /** {@hide} */
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_NO_ERROR = 0;
- /** {@hide} */
- public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
- /** {@hide} */
- public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
- /** {@hide} */
- public static final int TETHER_ERROR_UNSUPPORTED = 3;
- /** {@hide} */
- public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
- /** {@hide} */
- public static final int TETHER_ERROR_MASTER_ERROR = 5;
- /** {@hide} */
- public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
- /** {@hide} */
- public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
- /** {@hide} */
- public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8;
- /** {@hide} */
- public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9;
- /** {@hide} */
- public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
- /** {@hide} */
+ @Deprecated
+ public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNKNOWN_IFACE =
+ TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_SERVICE_UNAVAIL =
+ TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNAVAIL_IFACE =
+ TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_MASTER_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_MASTER_ERROR = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_TETHER_IFACE_ERROR =
+ TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
+ TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_NAT_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
+ TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_NAT_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
+ TetheringManager.TETHER_ERROR_DISABLE_NAT_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_IFACE_CFG_ERROR =
+ TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISION_FAILED}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_PROVISION_FAILED = 11;
- /** {@hide} */
- public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
- /** {@hide} */
+ @Deprecated
+ public static final int TETHER_ERROR_PROVISION_FAILED =
+ TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_DHCPSERVER_ERROR =
+ TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
+ @Deprecated
+ public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN =
+ TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
/**
* Get a more detailed error code after a Tethering or Untethering
@@ -2745,10 +2894,12 @@ public class ConnectivityManager {
* @return error The error code of the last error tethering or untethering the named
* interface
*
+ * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public int getLastTetherError(String iface) {
return getTetheringManager().getLastTetherError(iface);
}
@@ -2766,9 +2917,12 @@ public class ConnectivityManager {
/**
* Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
* entitlement succeeded.
+ *
+ * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead.
* @hide
*/
@SystemApi
+ @Deprecated
public interface OnTetheringEntitlementResultListener {
/**
* Called to notify entitlement result.
@@ -2798,9 +2952,11 @@ public class ConnectivityManager {
* @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
* notify the caller of the result of entitlement check. The listener may be called zero
* or one time.
+ * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead.
* {@hide}
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
@NonNull @CallbackExecutor Executor executor,
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index bf8b38fc7f84..8d9f0d068a57 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -19,6 +19,7 @@ package android.net;
import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED;
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
import static android.system.OsConstants.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -34,6 +35,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Pair;
import java.net.Inet4Address;
@@ -41,6 +43,7 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
+import java.util.Objects;
/**
* Identifies an IP address on a network link.
@@ -58,6 +61,21 @@ import java.net.UnknownHostException;
* </ul>
*/
public class LinkAddress implements Parcelable {
+
+ /**
+ * Indicates the deprecation or expiration time is unknown
+ * @hide
+ */
+ @SystemApi
+ public static final long LIFETIME_UNKNOWN = -1;
+
+ /**
+ * Indicates this address is permanent.
+ * @hide
+ */
+ @SystemApi
+ public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
+
/**
* IPv4 or IPv6 address.
*/
@@ -71,7 +89,9 @@ public class LinkAddress implements Parcelable {
private int prefixLength;
/**
- * Address flags. A bitmask of IFA_F_* values.
+ * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
+ * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
+ * flag depending on the current preferred lifetime.
*/
private int flags;
@@ -81,6 +101,23 @@ public class LinkAddress implements Parcelable {
private int scope;
/**
+ * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
+ * or was deprecated. {@link #LIFETIME_UNKNOWN} indicates this information is not available. At
+ * the time existing connections can still use this address until it expires, but new
+ * connections should use the new address. {@link #LIFETIME_PERMANENT} indicates this
+ * {@link LinkAddress} will never be deprecated.
+ */
+ private long deprecationTime;
+
+ /**
+ * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
+ * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
+ * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+ * will never expire.
+ */
+ private long expirationTime;
+
+ /**
* Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
* RFC 6724 section 3.2.
* @hide
@@ -152,7 +189,8 @@ public class LinkAddress implements Parcelable {
/**
* Utility function for the constructors.
*/
- private void init(InetAddress address, int prefixLength, int flags, int scope) {
+ private void init(InetAddress address, int prefixLength, int flags, int scope,
+ long deprecationTime, long expirationTime) {
if (address == null ||
address.isMulticastAddress() ||
prefixLength < 0 ||
@@ -161,15 +199,42 @@ public class LinkAddress implements Parcelable {
throw new IllegalArgumentException("Bad LinkAddress params " + address +
"/" + prefixLength);
}
+
+ // deprecation time and expiration time must be both provided, or neither.
+ if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
+ throw new IllegalArgumentException(
+ "Must not specify only one of deprecation time and expiration time");
+ }
+
+ // deprecation time needs to be a positive value.
+ if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
+ throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
+ }
+
+ // expiration time needs to be a positive value.
+ if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
+ throw new IllegalArgumentException("invalid expiration time " + expirationTime);
+ }
+
+ // expiration time can't be earlier than deprecation time
+ if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
+ && expirationTime < deprecationTime) {
+ throw new IllegalArgumentException("expiration earlier than deprecation ("
+ + deprecationTime + ", " + expirationTime + ")");
+ }
+
this.address = address;
this.prefixLength = prefixLength;
this.flags = flags;
this.scope = scope;
+ this.deprecationTime = deprecationTime;
+ this.expirationTime = expirationTime;
}
/**
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
* the specified flags and scope. Flags and scope are not checked for validity.
+ *
* @param address The IP address.
* @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
* @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
@@ -181,7 +246,39 @@ public class LinkAddress implements Parcelable {
@TestApi
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
int flags, int scope) {
- init(address, prefixLength, flags, scope);
+ init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
+ }
+
+ /**
+ * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
+ * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
+ * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
+ * flag will be adjusted based on the passed-in lifetimes.
+ *
+ * @param address The IP address.
+ * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
+ * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * @param scope An integer defining the scope in which the address is unique (e.g.,
+ * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
+ * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
+ * this {@link LinkAddress} will be or was deprecated.
+ * {@link #LIFETIME_UNKNOWN} indicates this information is not available.
+ * At the time existing connections can still use this address until it
+ * expires, but new connections should use the new address.
+ * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+ * never be deprecated.
+ * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
+ * {@link LinkAddress} will expire and be removed from the interface.
+ * {@link #LIFETIME_UNKNOWN} indicates this information is not available.
+ * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+ * never expire.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
+ int flags, int scope, long deprecationTime, long expirationTime) {
+ init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
}
/**
@@ -237,7 +334,7 @@ public class LinkAddress implements Parcelable {
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
- init(ipAndMask.first, ipAndMask.second, flags, scope);
+ init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
}
/**
@@ -265,10 +362,12 @@ public class LinkAddress implements Parcelable {
return false;
}
LinkAddress linkAddress = (LinkAddress) obj;
- return this.address.equals(linkAddress.address) &&
- this.prefixLength == linkAddress.prefixLength &&
- this.flags == linkAddress.flags &&
- this.scope == linkAddress.scope;
+ return this.address.equals(linkAddress.address)
+ && this.prefixLength == linkAddress.prefixLength
+ && this.flags == linkAddress.flags
+ && this.scope == linkAddress.scope
+ && this.deprecationTime == linkAddress.deprecationTime
+ && this.expirationTime == linkAddress.expirationTime;
}
/**
@@ -276,7 +375,7 @@ public class LinkAddress implements Parcelable {
*/
@Override
public int hashCode() {
- return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
+ return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
}
/**
@@ -329,6 +428,25 @@ public class LinkAddress implements Parcelable {
* Returns the flags of this {@code LinkAddress}.
*/
public int getFlags() {
+ int flags = this.flags;
+ if (deprecationTime != LIFETIME_UNKNOWN) {
+ if (SystemClock.elapsedRealtime() >= deprecationTime) {
+ flags |= IFA_F_DEPRECATED;
+ } else {
+ // If deprecation time is in the future, or permanent.
+ flags &= ~IFA_F_DEPRECATED;
+ }
+ }
+
+ if (expirationTime == LIFETIME_PERMANENT) {
+ flags |= IFA_F_PERMANENT;
+ } else if (expirationTime != LIFETIME_UNKNOWN) {
+ // If we know this address expired or will expire in the future or, then this address
+ // should not be permanent.
+ flags &= ~IFA_F_PERMANENT;
+ }
+
+ // Do no touch the original flags. Return the adjusted flags here.
return flags;
}
@@ -340,7 +458,35 @@ public class LinkAddress implements Parcelable {
}
/**
- * Returns true if this {@code LinkAddress} is global scope and preferred.
+ * @return The time that this address will be deprecated. At the time the existing connection
+ * can still use this address until it expires, but the new connection should use the new
+ * address. This is the EPOCH time in milliseconds. 0 indicates this information is not
+ * available.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public long getDeprecationTime() {
+ return deprecationTime;
+ }
+
+ /**
+ * @return The time that this address will expire and will be no longer valid. This is the EPOCH
+ * time in milliseconds. 0 indicates this information is not available.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public long getExpirationTime() {
+ return expirationTime;
+ }
+
+ /**
+ * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
+ * deprecated).
+ *
* @hide
*/
@TestApi
@@ -352,6 +498,7 @@ public class LinkAddress implements Parcelable {
* state has cleared either DAD has succeeded or failed, and both
* flags are cleared regardless).
*/
+ int flags = getFlags();
return (scope == RT_SCOPE_UNIVERSE
&& !isIpv6ULA()
&& (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
@@ -373,6 +520,8 @@ public class LinkAddress implements Parcelable {
dest.writeInt(prefixLength);
dest.writeInt(this.flags);
dest.writeInt(scope);
+ dest.writeLong(deprecationTime);
+ dest.writeLong(expirationTime);
}
/**
@@ -392,7 +541,10 @@ public class LinkAddress implements Parcelable {
int prefixLength = in.readInt();
int flags = in.readInt();
int scope = in.readInt();
- return new LinkAddress(address, prefixLength, flags, scope);
+ long deprecationTime = in.readLong();
+ long expirationTime = in.readLong();
+ return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
+ expirationTime);
}
public LinkAddress[] newArray(int size) {
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7cc78f7389c2..7cc569a42b0b 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -304,7 +304,10 @@ public abstract class NetworkAgent {
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with the type and an empty description.
- return new NetworkInfo(config.legacyType, config.legacyType, config.legacyTypeName, "");
+ final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType,
+ config.legacyTypeName, "");
+ ni.setIsAvailable(true);
+ return ni;
}
/**
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 47c08a450fc4..4469d7de28fb 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -73,13 +73,14 @@ public class NetworkKey implements Parcelable {
/**
* Constructs a new NetworkKey for the given wifi {@link ScanResult}.
*
- * @return A new {@link NetworkKey} instance or <code>null</code> if the given
- * {@link ScanResult} instance is malformed.
+ * @return A new {@link NetworkKey} instance or <code>null</code> if the given
+ * {@link ScanResult} instance is malformed.
+ * @throws IllegalArgumentException
*/
@Nullable
- public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
+ public static NetworkKey createFromScanResult(@NonNull ScanResult result) {
if (result == null) {
- return null;
+ throw new IllegalArgumentException("ScanResult cannot be null");
}
final String ssid = result.SSID;
if (TextUtils.isEmpty(ssid) || ssid.equals(WifiManager.UNKNOWN_SSID)) {
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index c233ec0e52cf..a190c473f0a0 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -35,6 +35,7 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
@@ -385,7 +386,6 @@ public class NetworkScoreManager {
*
* @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public boolean requestScores(@NonNull NetworkKey[] networks) throws SecurityException {
try {
@@ -396,6 +396,28 @@ public class NetworkScoreManager {
}
/**
+ * Request scoring for networks.
+ *
+ * <p>
+ * Note: The results (i.e scores) for these networks, when available will be provided via the
+ * callback registered with {@link #registerNetworkScoreCallback(int, int, Executor,
+ * NetworkScoreCallback)}. The calling module is responsible for registering a callback to
+ * receive the results before requesting new scores via this API.
+ *
+ * @return true if the request was successfully sent, or false if there is no active scorer.
+ * @throws SecurityException if the caller does not hold the
+ * {@link permission#REQUEST_NETWORK_SCORES} permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
+ public boolean requestScores(@NonNull Collection<NetworkKey> networks)
+ throws SecurityException {
+ return requestScores(networks.toArray(new NetworkKey[0]));
+ }
+
+ /**
* Register a network score cache.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
@@ -454,26 +476,25 @@ public class NetworkScoreManager {
/**
* Base class for network score cache callback. Should be extended by applications and set
- * when calling {@link #registerNetworkScoreCallback(int, int, NetworkScoreCallback,
- * Executor)}
+ * when calling {@link #registerNetworkScoreCallback(int, int, Executor, NetworkScoreCallback)}.
*
* @hide
*/
@SystemApi
- public interface NetworkScoreCallback {
+ public abstract static class NetworkScoreCallback {
/**
* Called when a new set of network scores are available.
* This is triggered in response when the client invokes
- * {@link #requestScores(NetworkKey[])} to score a new set of networks.
+ * {@link #requestScores(Collection)} to score a new set of networks.
*
* @param networks List of {@link ScoredNetwork} containing updated scores.
*/
- void updateScores(@NonNull List<ScoredNetwork> networks);
+ public abstract void onScoresUpdated(@NonNull Collection<ScoredNetwork> networks);
/**
* Invokes when all the previously provided scores are no longer valid.
*/
- void clearScores();
+ public abstract void onScoresInvalidated();
}
/**
@@ -492,7 +513,7 @@ public class NetworkScoreManager {
public void updateScores(@NonNull List<ScoredNetwork> networks) {
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
- mCallback.updateScores(networks);
+ mCallback.onScoresUpdated(networks);
});
}
@@ -500,7 +521,7 @@ public class NetworkScoreManager {
public void clearScores() {
Binder.clearCallingIdentity();
mExecutor.execute(() -> {
- mCallback.clearScores();
+ mCallback.onScoresInvalidated();
});
}
}
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
index 83dbc637fb65..6ae59716cfd8 100644
--- a/core/java/android/net/StringNetworkSpecifier.java
+++ b/core/java/android/net/StringNetworkSpecifier.java
@@ -17,7 +17,6 @@
package android.net;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -27,7 +26,6 @@ import com.android.internal.util.Preconditions;
import java.util.Objects;
/** @hide */
-@SystemApi
public final class StringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
/**
* Arbitrary string used to pass (additional) information to the network factory.
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 0545666ca743..f2e16b46422f 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -42,7 +42,7 @@ import java.lang.annotation.RetentionPolicy;
*/
@SystemApi
@SystemService(Context.BATTERY_STATS_SERVICE)
-public class BatteryStatsManager {
+public final class BatteryStatsManager {
/**
* Wifi states.
*
@@ -166,7 +166,7 @@ public class BatteryStatsManager {
* @param newRssi The new RSSI value.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiRssiChanged(@IntRange(from = -127, to = 0) int newRssi) {
+ public void reportWifiRssiChanged(@IntRange(from = -127, to = 0) int newRssi) {
try {
mBatteryStats.noteWifiRssiChanged(newRssi);
} catch (RemoteException e) {
@@ -178,7 +178,7 @@ public class BatteryStatsManager {
* Indicates that wifi was toggled on.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiOn() {
+ public void reportWifiOn() {
try {
mBatteryStats.noteWifiOn();
} catch (RemoteException e) {
@@ -190,7 +190,7 @@ public class BatteryStatsManager {
* Indicates that wifi was toggled off.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiOff() {
+ public void reportWifiOff() {
try {
mBatteryStats.noteWifiOff();
} catch (RemoteException e) {
@@ -205,7 +205,7 @@ public class BatteryStatsManager {
* @param accessPoint SSID of the network if wifi is connected to STA, else null.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiState(@WifiState int newWifiState,
+ public void reportWifiState(@WifiState int newWifiState,
@Nullable String accessPoint) {
try {
mBatteryStats.noteWifiState(newWifiState, accessPoint);
@@ -220,7 +220,7 @@ public class BatteryStatsManager {
* @param ws Worksource (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiScanStartedFromSource(@NonNull WorkSource ws) {
+ public void reportWifiScanStartedFromSource(@NonNull WorkSource ws) {
try {
mBatteryStats.noteWifiScanStartedFromSource(ws);
} catch (RemoteException e) {
@@ -234,7 +234,7 @@ public class BatteryStatsManager {
* @param ws Worksource (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiScanStoppedFromSource(@NonNull WorkSource ws) {
+ public void reportWifiScanStoppedFromSource(@NonNull WorkSource ws) {
try {
mBatteryStats.noteWifiScanStoppedFromSource(ws);
} catch (RemoteException e) {
@@ -249,7 +249,7 @@ public class BatteryStatsManager {
* @param csph Channels scanned per hour.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiBatchedScanStartedFromSource(@NonNull WorkSource ws,
+ public void reportWifiBatchedScanStartedFromSource(@NonNull WorkSource ws,
@IntRange(from = 0) int csph) {
try {
mBatteryStats.noteWifiBatchedScanStartedFromSource(ws, csph);
@@ -264,7 +264,7 @@ public class BatteryStatsManager {
* @param ws Worksource (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiBatchedScanStoppedFromSource(@NonNull WorkSource ws) {
+ public void reportWifiBatchedScanStoppedFromSource(@NonNull WorkSource ws) {
try {
mBatteryStats.noteWifiBatchedScanStoppedFromSource(ws);
} catch (RemoteException e) {
@@ -308,7 +308,7 @@ public class BatteryStatsManager {
* @param ws Worksource (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteFullWifiLockAcquiredFromSource(@NonNull WorkSource ws) {
+ public void reportFullWifiLockAcquiredFromSource(@NonNull WorkSource ws) {
try {
mBatteryStats.noteFullWifiLockAcquiredFromSource(ws);
} catch (RemoteException e) {
@@ -322,7 +322,7 @@ public class BatteryStatsManager {
* @param ws Worksource (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteFullWifiLockReleasedFromSource(@NonNull WorkSource ws) {
+ public void reportFullWifiLockReleasedFromSource(@NonNull WorkSource ws) {
try {
mBatteryStats.noteFullWifiLockReleasedFromSource(ws);
} catch (RemoteException e) {
@@ -338,7 +338,7 @@ public class BatteryStatsManager {
* authentication failure.
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiSupplicantStateChanged(@WifiSupplState int newSupplState,
+ public void reportWifiSupplicantStateChanged(@WifiSupplState int newSupplState,
boolean failedAuth) {
try {
mBatteryStats.noteWifiSupplicantStateChanged(newSupplState, failedAuth);
@@ -353,7 +353,7 @@ public class BatteryStatsManager {
* @param uid UID of the app that acquired the wifi lock (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiMulticastEnabled(int uid) {
+ public void reportWifiMulticastEnabled(int uid) {
try {
mBatteryStats.noteWifiMulticastEnabled(uid);
} catch (RemoteException e) {
@@ -367,7 +367,7 @@ public class BatteryStatsManager {
* @param uid UID of the app that released the wifi lock (to be used for battery blaming).
*/
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
- public void noteWifiMulticastDisabled(int uid) {
+ public void reportWifiMulticastDisabled(int uid) {
try {
mBatteryStats.noteWifiMulticastDisabled(uid);
} catch (RemoteException e) {
diff --git a/core/java/android/os/StatsServiceManager.java b/core/java/android/os/StatsServiceManager.java
new file mode 100644
index 000000000000..d032e98da00c
--- /dev/null
+++ b/core/java/android/os/StatsServiceManager.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+/**
+ * Provides a way to register and obtain the system service binder objects managed by the stats
+ * service.
+ *
+ * <p> Only the statsd mainline module will be able to access an instance of this class.
+ *
+ * TODO(b/148225705) Change to @SystemApi(client=MODULE_LIBRARIES) when the build system is ready.
+ * @hide
+ */
+@SystemApi
+public class StatsServiceManager {
+ /**
+ * @hide
+ */
+ public StatsServiceManager() {}
+
+ /**
+ * A class that exposes the methods to register and obtain each system service.
+ */
+ public static final class ServiceRegisterer {
+ private final String mServiceName;
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName) {
+ mServiceName = serviceName;
+ }
+
+ /**
+ * Get the system server binding object for StatsManagerService.
+ *
+ * <p> This blocks until the service instance is ready.
+ * or a timeout happens, in which case it returns null.
+ */
+ @Nullable
+ public IBinder get() {
+ return ServiceManager.getService(mServiceName);
+ }
+
+ /**
+ * Get the system server binding object for a service.
+ *
+ * <p>This blocks until the service instance is ready,
+ * or a timeout happens, in which case it throws {@link ServiceNotFoundException}.
+ */
+ @Nullable
+ public IBinder getOrThrow() throws ServiceNotFoundException {
+ try {
+ return ServiceManager.getServiceOrThrow(mServiceName);
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new ServiceNotFoundException(mServiceName);
+ }
+ }
+
+ /**
+ * Get the system server binding object for a service. If the specified service is
+ * not available, it returns null.
+ */
+ @Nullable
+ private IBinder tryGet() {
+ return ServiceManager.checkService(mServiceName);
+ }
+ }
+
+ /**
+ * See {@link ServiceRegisterer#getOrThrow()}
+ */
+ public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException {
+ /**
+ * Constructor
+ *
+ * @param name the name of the binder service that cannot be found.
+ */
+ public ServiceNotFoundException(@NonNull String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "statscompanion" service.
+ */
+ @NonNull
+ public ServiceRegisterer getStatsCompanionServiceRegisterer() {
+ return new ServiceRegisterer("statscompanion");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "statsmanager" service.
+ */
+ @NonNull
+ public ServiceRegisterer getStatsManagerServiceRegisterer() {
+ return new ServiceRegisterer("statsmanager");
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "statsd" service.
+ */
+ @NonNull
+ public ServiceRegisterer getStatsdServiceRegisterer() {
+ return new ServiceRegisterer("stats");
+ }
+}
diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java
index 4f5f3d69b6f3..c93eba6523f0 100644
--- a/core/java/android/os/TelephonyServiceManager.java
+++ b/core/java/android/os/TelephonyServiceManager.java
@@ -119,14 +119,6 @@ public class TelephonyServiceManager {
}
/**
- * 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
@@ -151,14 +143,6 @@ public class TelephonyServiceManager {
}
/**
- * 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
@@ -198,6 +182,9 @@ public class TelephonyServiceManager {
return new ServiceRegisterer("econtroller");
}
+ /**
+ * Returns {@link ServiceRegisterer} for the eUICC card controller service.
+ */
@NonNull
public ServiceRegisterer getEuiccCardControllerServiceRegisterer() {
return new ServiceRegisterer("euicc_card_controller");
@@ -212,14 +199,6 @@ public class TelephonyServiceManager {
}
/**
- * 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
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index 895d837a359e..3c30f6343405 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -15,11 +15,13 @@
*/
package android.os.connectivity;
+import static android.os.BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS;
+import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
+import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.os.BatteryStats;
-import android.os.BatteryStatsManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,31 +35,50 @@ import java.util.Objects;
*/
@SystemApi
public final class WifiBatteryStats implements Parcelable {
- private long mLoggingDurationMillis = 0;
- private long mKernelActiveTimeMillis = 0;
- private long mNumPacketsTx = 0;
- private long mNumBytesTx = 0;
- private long mNumPacketsRx = 0;
- private long mNumBytesRx = 0;
- private long mSleepTimeMillis = 0;
- private long mScanTimeMillis = 0;
- private long mIdleTimeMillis = 0;
- private long mRxTimeMillis = 0;
- private long mTxTimeMillis = 0;
- private long mEnergyConsumedMaMillis = 0;
- private long mNumAppScanRequest = 0;
- private long[] mTimeInStateMillis =
- new long[BatteryStatsManager.NUM_WIFI_STATES];
- private long[] mTimeInSupplicantStateMillis =
- new long[BatteryStatsManager.NUM_WIFI_SUPPL_STATES];
- private long[] mTimeInRxSignalStrengthLevelMillis =
- new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
- private long mMonitoredRailChargeConsumedMaMillis = 0;
+ private final long mLoggingDurationMillis;
+ private final long mKernelActiveTimeMillis;
+ private final long mNumPacketsTx;
+ private final long mNumBytesTx;
+ private final long mNumPacketsRx;
+ private final long mNumBytesRx;
+ private final long mSleepTimeMillis;
+ private final long mScanTimeMillis;
+ private final long mIdleTimeMillis;
+ private final long mRxTimeMillis;
+ private final long mTxTimeMillis;
+ private final long mEnergyConsumedMaMillis;
+ private final long mAppScanRequestCount;
+ private final long[] mTimeInStateMillis;
+ private final long[] mTimeInSupplicantStateMillis;
+ private final long[] mTimeInRxSignalStrengthLevelMillis;
+ private final long mMonitoredRailChargeConsumedMaMillis;
public static final @NonNull Parcelable.Creator<WifiBatteryStats> CREATOR =
new Parcelable.Creator<WifiBatteryStats>() {
public WifiBatteryStats createFromParcel(Parcel in) {
- return new WifiBatteryStats(in);
+ long loggingDurationMillis = in.readLong();
+ long kernelActiveTimeMillis = in.readLong();
+ long numPacketsTx = in.readLong();
+ long numBytesTx = in.readLong();
+ long numPacketsRx = in.readLong();
+ long numBytesRx = in.readLong();
+ long sleepTimeMillis = in.readLong();
+ long scanTimeMillis = in.readLong();
+ long idleTimeMillis = in.readLong();
+ long rxTimeMillis = in.readLong();
+ long txTimeMillis = in.readLong();
+ long energyConsumedMaMillis = in.readLong();
+ long appScanRequestCount = in.readLong();
+ long[] timeInStateMillis = in.createLongArray();
+ long[] timeInRxSignalStrengthLevelMillis = in.createLongArray();
+ long[] timeInSupplicantStateMillis = in.createLongArray();
+ long monitoredRailChargeConsumedMaMillis = in.readLong();
+ return new WifiBatteryStats(loggingDurationMillis, kernelActiveTimeMillis,
+ numPacketsTx, numBytesTx, numPacketsRx, numBytesRx, sleepTimeMillis,
+ scanTimeMillis, idleTimeMillis, rxTimeMillis, txTimeMillis,
+ energyConsumedMaMillis, appScanRequestCount, timeInStateMillis,
+ timeInRxSignalStrengthLevelMillis, timeInSupplicantStateMillis,
+ monitoredRailChargeConsumedMaMillis);
}
public WifiBatteryStats[] newArray(int size) {
@@ -84,7 +105,7 @@ public final class WifiBatteryStats implements Parcelable {
out.writeLong(mRxTimeMillis);
out.writeLong(mTxTimeMillis);
out.writeLong(mEnergyConsumedMaMillis);
- out.writeLong(mNumAppScanRequest);
+ out.writeLong(mAppScanRequestCount);
out.writeLongArray(mTimeInStateMillis);
out.writeLongArray(mTimeInRxSignalStrengthLevelMillis);
out.writeLongArray(mTimeInSupplicantStateMillis);
@@ -108,7 +129,7 @@ public final class WifiBatteryStats implements Parcelable {
&& this.mRxTimeMillis == otherStats.mRxTimeMillis
&& this.mTxTimeMillis == otherStats.mTxTimeMillis
&& this.mEnergyConsumedMaMillis == otherStats.mEnergyConsumedMaMillis
- && this.mNumAppScanRequest == otherStats.mNumAppScanRequest
+ && this.mAppScanRequestCount == otherStats.mAppScanRequestCount
&& Arrays.equals(this.mTimeInStateMillis, otherStats.mTimeInStateMillis)
&& Arrays.equals(this.mTimeInSupplicantStateMillis,
otherStats.mTimeInSupplicantStateMillis)
@@ -123,33 +144,42 @@ public final class WifiBatteryStats implements Parcelable {
return Objects.hash(mLoggingDurationMillis, mKernelActiveTimeMillis, mNumPacketsTx,
mNumBytesTx, mNumPacketsRx, mNumBytesRx, mSleepTimeMillis, mScanTimeMillis,
mIdleTimeMillis, mRxTimeMillis, mTxTimeMillis, mEnergyConsumedMaMillis,
- mNumAppScanRequest, Arrays.hashCode(mTimeInStateMillis),
+ mAppScanRequestCount, Arrays.hashCode(mTimeInStateMillis),
Arrays.hashCode(mTimeInSupplicantStateMillis),
Arrays.hashCode(mTimeInRxSignalStrengthLevelMillis),
mMonitoredRailChargeConsumedMaMillis);
}
/** @hide **/
- public WifiBatteryStats() {}
-
- private void readFromParcel(Parcel in) {
- mLoggingDurationMillis = in.readLong();
- mKernelActiveTimeMillis = in.readLong();
- mNumPacketsTx = in.readLong();
- mNumBytesTx = in.readLong();
- mNumPacketsRx = in.readLong();
- mNumBytesRx = in.readLong();
- mSleepTimeMillis = in.readLong();
- mScanTimeMillis = in.readLong();
- mIdleTimeMillis = in.readLong();
- mRxTimeMillis = in.readLong();
- mTxTimeMillis = in.readLong();
- mEnergyConsumedMaMillis = in.readLong();
- mNumAppScanRequest = in.readLong();
- in.readLongArray(mTimeInStateMillis);
- in.readLongArray(mTimeInRxSignalStrengthLevelMillis);
- in.readLongArray(mTimeInSupplicantStateMillis);
- mMonitoredRailChargeConsumedMaMillis = in.readLong();
+ public WifiBatteryStats(long loggingDurationMillis, long kernelActiveTimeMillis,
+ long numPacketsTx, long numBytesTx, long numPacketsRx, long numBytesRx,
+ long sleepTimeMillis, long scanTimeMillis, long idleTimeMillis, long rxTimeMillis,
+ long txTimeMillis, long energyConsumedMaMillis, long appScanRequestCount,
+ @NonNull long[] timeInStateMillis, @NonNull long [] timeInRxSignalStrengthLevelMillis,
+ @NonNull long[] timeInSupplicantStateMillis, long monitoredRailChargeConsumedMaMillis) {
+ mLoggingDurationMillis = loggingDurationMillis;
+ mKernelActiveTimeMillis = kernelActiveTimeMillis;
+ mNumPacketsTx = numPacketsTx;
+ mNumBytesTx = numBytesTx;
+ mNumPacketsRx = numPacketsRx;
+ mNumBytesRx = numBytesRx;
+ mSleepTimeMillis = sleepTimeMillis;
+ mScanTimeMillis = scanTimeMillis;
+ mIdleTimeMillis = idleTimeMillis;
+ mRxTimeMillis = rxTimeMillis;
+ mTxTimeMillis = txTimeMillis;
+ mEnergyConsumedMaMillis = energyConsumedMaMillis;
+ mAppScanRequestCount = appScanRequestCount;
+ mTimeInStateMillis = Arrays.copyOfRange(
+ timeInStateMillis, 0,
+ Math.min(timeInStateMillis.length, NUM_WIFI_STATES));
+ mTimeInRxSignalStrengthLevelMillis = Arrays.copyOfRange(
+ timeInRxSignalStrengthLevelMillis, 0,
+ Math.min(timeInRxSignalStrengthLevelMillis.length, NUM_WIFI_SIGNAL_STRENGTH_BINS));
+ mTimeInSupplicantStateMillis = Arrays.copyOfRange(
+ timeInSupplicantStateMillis, 0,
+ Math.min(timeInSupplicantStateMillis.length, NUM_WIFI_SUPPL_STATES));
+ mMonitoredRailChargeConsumedMaMillis = monitoredRailChargeConsumedMaMillis;
}
/**
@@ -182,7 +212,7 @@ public final class WifiBatteryStats implements Parcelable {
}
/**
- * Returns the number of packets received over wifi within
+ * Returns the number of bytes transmitted over wifi within
* {@link #getLoggingDurationMillis()}.
*
* @return Number of packets received.
@@ -192,7 +222,7 @@ public final class WifiBatteryStats implements Parcelable {
}
/**
- * Returns the number of bytes transmitted over wifi within
+ * Returns the number of packets received over wifi within
* {@link #getLoggingDurationMillis()}.
*
* @return Number of bytes transmitted.
@@ -262,7 +292,7 @@ public final class WifiBatteryStats implements Parcelable {
}
/**
- * Returns an estimation of energy consumed by wifi chip within
+ * Returns an estimation of energy consumed in millis by wifi chip within
* {@link #getLoggingDurationMillis()}.
*
* @return Energy consumed in millis.
@@ -276,8 +306,8 @@ public final class WifiBatteryStats implements Parcelable {
*
* @return Number of app scans.
*/
- public long getNumAppScanRequest() {
- return mNumAppScanRequest;
+ public long getAppScanRequestCount() {
+ return mAppScanRequestCount;
}
/**
@@ -288,113 +318,4 @@ public final class WifiBatteryStats implements Parcelable {
public long getMonitoredRailChargeConsumedMaMillis() {
return mMonitoredRailChargeConsumedMaMillis;
}
-
- /** @hide */
- public void setLoggingDurationMillis(long t) {
- mLoggingDurationMillis = t;
- return;
- }
-
- /** @hide */
- public void setKernelActiveTimeMillis(long t) {
- mKernelActiveTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setNumPacketsTx(long n) {
- mNumPacketsTx = n;
- return;
- }
-
- /** @hide */
- public void setNumBytesTx(long b) {
- mNumBytesTx = b;
- return;
- }
-
- /** @hide */
- public void setNumPacketsRx(long n) {
- mNumPacketsRx = n;
- return;
- }
-
- /** @hide */
- public void setNumBytesRx(long b) {
- mNumBytesRx = b;
- return;
- }
-
- /** @hide */
- public void setSleepTimeMillis(long t) {
- mSleepTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setScanTimeMillis(long t) {
- mScanTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setIdleTimeMillis(long t) {
- mIdleTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setRxTimeMillis(long t) {
- mRxTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setTxTimeMillis(long t) {
- mTxTimeMillis = t;
- return;
- }
-
- /** @hide */
- public void setEnergyConsumedMaMillis(long e) {
- mEnergyConsumedMaMillis = e;
- return;
- }
-
- /** @hide */
- public void setNumAppScanRequest(long n) {
- mNumAppScanRequest = n;
- return;
- }
-
- /** @hide */
- public void setTimeInStateMillis(long[] t) {
- mTimeInStateMillis = Arrays.copyOfRange(t, 0,
- Math.min(t.length, BatteryStatsManager.NUM_WIFI_STATES));
- return;
- }
-
- /** @hide */
- public void setTimeInRxSignalStrengthLevelMillis(long[] t) {
- mTimeInRxSignalStrengthLevelMillis = Arrays.copyOfRange(t, 0,
- Math.min(t.length, BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS));
- return;
- }
-
- /** @hide */
- public void setTimeInSupplicantStateMillis(long[] t) {
- mTimeInSupplicantStateMillis = Arrays.copyOfRange(
- t, 0, Math.min(t.length, BatteryStatsManager.NUM_WIFI_SUPPL_STATES));
- return;
- }
-
- /** @hide */
- public void setMonitoredRailChargeConsumedMaMillis(long monitoredRailEnergyConsumedMaMillis) {
- mMonitoredRailChargeConsumedMaMillis = monitoredRailEnergyConsumedMaMillis;
- return;
- }
-
- private WifiBatteryStats(Parcel in) {
- readFromParcel(in);
- }
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 84ceca0c3622..091d78e88c98 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -796,6 +796,14 @@ public final class DeviceConfig {
}
/**
+ * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION;
+ * @hide
+ */
+ public static @NonNull List<String> getPublicNamespaces() {
+ return PUBLIC_NAMESPACES;
+ }
+
+ /**
* Interface for monitoring changes to properties. Implementations will receive callbacks when
* properties change, including a {@link Properties} object which contains a single namespace
* and all of the properties which changed for that namespace. This includes properties which
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c7c3140f7365..00b2feba8bcd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -63,6 +63,7 @@ import android.os.IBinder;
import android.os.LocaleList;
import android.os.PowerManager.AutoPowerSaveModeTriggers;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -2161,6 +2162,11 @@ public final class Settings {
public static final String CALL_METHOD_PREFIX_KEY = "_prefix";
/**
+ * @hide - RemoteCallback monitor callback argument extra to the fast-path call()-based requests
+ */
+ public static final String CALL_METHOD_MONITOR_CALLBACK_KEY = "_monitor_callback_key";
+
+ /**
* @hide - String argument extra to the fast-path call()-based requests
*/
public static final String CALL_METHOD_FLAGS_KEY = "_flags";
@@ -2218,6 +2224,26 @@ public final class Settings {
/** @hide - Private call() method to reset to defaults the 'configuration' table */
public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+ /** @hide - Private call() method to register monitor callback for 'configuration' table */
+ public static final String CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG =
+ "REGISTER_MONITOR_CALLBACK_config";
+
+ /** @hide - String argument extra to the config monitor callback */
+ public static final String EXTRA_MONITOR_CALLBACK_TYPE = "monitor_callback_type";
+
+ /** @hide - String argument extra to the config monitor callback */
+ public static final String EXTRA_ACCESS_CALLBACK = "access_callback";
+
+ /** @hide - String argument extra to the config monitor callback */
+ public static final String EXTRA_NAMESPACE_UPDATED_CALLBACK =
+ "namespace_updated_callback";
+
+ /** @hide - String argument extra to the config monitor callback */
+ public static final String EXTRA_NAMESPACE = "namespace";
+
+ /** @hide - String argument extra to the config monitor callback */
+ public static final String EXTRA_CALLING_PACKAGE = "calling_package";
+
/**
* Activity Extra: Limit available options in launched activity based on the given authority.
* <p>
@@ -14155,6 +14181,37 @@ public final class Settings {
}
}
+ /**
+ * Register callback for monitoring Config table.
+ *
+ * @param resolver Handle to the content resolver.
+ * @param callback callback to register
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS)
+ public static void registerMonitorCallback(@NonNull ContentResolver resolver,
+ @NonNull RemoteCallback callback) {
+ registerMonitorCallbackAsUser(resolver, resolver.getUserId(), callback);
+ }
+
+ private static void registerMonitorCallbackAsUser(
+ @NonNull ContentResolver resolver, @UserIdInt int userHandle,
+ @NonNull RemoteCallback callback) {
+ try {
+ Bundle arg = new Bundle();
+ arg.putInt(CALL_METHOD_USER_KEY, userHandle);
+ arg.putParcelable(CALL_METHOD_MONITOR_CALLBACK_KEY, callback);
+ IContentProvider cp = sProviderHolder.getProvider(resolver);
+ cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+ sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG, null, arg);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't register config monitor callback", e);
+ }
+ }
+
private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(name);
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 453728137d9a..f25cdf1b8c98 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -37,7 +37,6 @@ import android.database.sqlite.SqliteWrapper;
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;
@@ -4559,32 +4558,6 @@ public final class Telephony {
}
/**
- * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
- *
- * @param state the ServiceState to convert into ContentValues
- * @return the convertedContentValues instance
- * @hide
- */
- public static ContentValues getContentValuesForServiceState(ServiceState state) {
- ContentValues values = new ContentValues();
- final Parcel p = Parcel.obtain();
- state.writeToParcel(p, 0);
- // Turn the parcel to byte array. Safe to do this because the content values were never
- // written into a persistent storage. ServiceStateProvider keeps values in the memory.
- values.put(SERVICE_STATE, p.marshall());
- return values;
- }
-
- /**
- * The current service state.
- *
- * This is the entire {@link ServiceState} object in byte array.
- *
- * @hide
- */
- public static final String SERVICE_STATE = "service_state";
-
- /**
* An integer value indicating the current voice service state.
* <p>
* Valid values: {@link ServiceState#STATE_IN_SERVICE},
@@ -4596,53 +4569,6 @@ public final class Telephony {
public static final String VOICE_REG_STATE = "voice_reg_state";
/**
- * An integer value indicating the current data service state.
- * <p>
- * Valid values: {@link ServiceState#STATE_IN_SERVICE},
- * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
- * {@link ServiceState#STATE_POWER_OFF}.
- * <p>
- * This is the same as {@link ServiceState#getDataRegState()}.
- * @hide
- */
- public static final String DATA_REG_STATE = "data_reg_state";
-
- /**
- * An integer value indicating the current voice roaming type.
- * <p>
- * This is the same as {@link ServiceState#getVoiceRoamingType()}.
- * @hide
- */
- public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
-
- /**
- * An integer value indicating the current data roaming type.
- * <p>
- * This is the same as {@link ServiceState#getDataRoamingType()}.
- * @hide
- */
- public static final String DATA_ROAMING_TYPE = "data_roaming_type";
-
- /**
- * The current registered voice network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
- * @hide
- */
- public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
-
- /**
- * The current registered operator name in short alphanumeric format.
- * <p>
- * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
- * network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
- * @hide
- */
- public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
-
- /**
* The current registered operator numeric id.
* <p>
* In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
@@ -4653,125 +4579,11 @@ public final class Telephony {
public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
/**
- * The current registered data network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
- * @hide
- */
- public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
-
- /**
- * The current registered data network operator name in short alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
- * @hide
- */
- public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
-
- /**
- * The current registered data network operator numeric id.
- * <p>
- * This is the same as {@link ServiceState#getOperatorNumeric()}.
- * @hide
- */
- public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
-
- /**
* The current network selection mode.
* <p>
* This is the same as {@link ServiceState#getIsManualSelection()}.
*/
public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
-
- /**
- * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
- * @hide
- */
- public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
-
- /**
- * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
- * @hide
- */
- public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
-
- /**
- * This is the same as {@link ServiceState#getCssIndicator()}.
- * @hide
- */
- public static final String CSS_INDICATOR = "css_indicator";
-
- /**
- * This is the same as {@link ServiceState#getCdmaNetworkId()}.
- * @hide
- */
- public static final String NETWORK_ID = "network_id";
-
- /**
- * This is the same as {@link ServiceState#getCdmaSystemId()}.
- * @hide
- */
- public static final String SYSTEM_ID = "system_id";
-
- /**
- * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
- * @hide
- */
- public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
-
- /**
- * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
- * @hide
- */
- public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
- "cdma_default_roaming_indicator";
-
- /**
- * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
- * @hide
- */
- public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
-
- /**
- * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
- * @hide
- */
- public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
-
- /**
- * This is the same as {@link ServiceState#isEmergencyOnly()}.
- * @hide
- */
- public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
-
- /**
- * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
- * @hide
- */
- public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
- "is_data_roaming_from_registration";
-
- /**
- * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
- * @hide
- */
- public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
-
- /**
- * The current registered raw data network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
- * @hide
- */
- public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
-
- /**
- * The current registered raw data network operator name in short alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
- * @hide
- */
- public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
}
/**
@@ -5299,6 +5111,12 @@ public final class Telephony {
public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
/**
+ * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+ * subscription.
+ */
+ public static final String IMS_RCS_UCE_ENABLED = "ims_rcs_uce_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.
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 5330cffee3db..f67af85d00e3 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -212,20 +212,16 @@ public class ConfirmationPrompt {
private int getUiOptionsAsFlags() {
int uiOptionsAsFlags = 0;
- try {
- ContentResolver contentResolver = mContext.getContentResolver();
- int inversionEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
- if (inversionEnabled == 1) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
- }
- float fontScale = Settings.System.getFloat(contentResolver,
- Settings.System.FONT_SCALE);
- if (fontScale > 1.0) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
- }
- } catch (SettingNotFoundException e) {
- Log.w(TAG, "Unexpected SettingNotFoundException");
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int inversionEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
+ if (inversionEnabled == 1) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
+ }
+ float fontScale = Settings.System.getFloat(contentResolver,
+ Settings.System.FONT_SCALE, (float) 1.0);
+ if (fontScale > 1.0) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
}
return uiOptionsAsFlags;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index dc0f5623e5e3..9333dbd1e1d5 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -87,6 +87,7 @@ public final class FillResponse implements Parcelable {
private final @Nullable UserData mUserData;
private final @Nullable int[] mCancelIds;
private final boolean mSupportsInlineSuggestions;
+ private final @Nullable ParceledListSlice<InlinePresentation> mInlineActions;
private FillResponse(@NonNull Builder builder) {
mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -105,6 +106,8 @@ public final class FillResponse implements Parcelable {
mUserData = builder.mUserData;
mCancelIds = builder.mCancelIds;
mSupportsInlineSuggestions = builder.mSupportsInlineSuggestions;
+ mInlineActions = (builder.mInlineActions != null) ? new ParceledListSlice<>(
+ builder.mInlineActions) : null;
}
/** @hide */
@@ -202,6 +205,11 @@ public final class FillResponse implements Parcelable {
return mSupportsInlineSuggestions;
}
+ /** @hide */
+ public @Nullable List<InlinePresentation> getInlineActions() {
+ return (mInlineActions != null) ? mInlineActions.getList() : null;
+ }
+
/**
* Builder for {@link FillResponse} objects. You must to provide at least
* one dataset or set an authentication intent with a presentation view.
@@ -223,6 +231,7 @@ public final class FillResponse implements Parcelable {
private UserData mUserData;
private int[] mCancelIds;
private boolean mSupportsInlineSuggestions;
+ private ArrayList<InlinePresentation> mInlineActions;
/**
* Triggers a custom UI before before autofilling the screen with any data set in this
@@ -578,6 +587,25 @@ public final class FillResponse implements Parcelable {
}
/**
+ * Adds a new {@link InlinePresentation} to this response representing an action UI.
+ *
+ * <p> For example, the UI can be associated with an intent which can open an activity for
+ * the user to manage the Autofill provider settings.
+ *
+ * @return This builder.
+ */
+ @NonNull
+ public Builder addInlineAction(@NonNull InlinePresentation inlineAction) {
+ throwIfDestroyed();
+ throwIfAuthenticationCalled();
+ if (mInlineActions == null) {
+ mInlineActions = new ArrayList<>();
+ }
+ mInlineActions.add(inlineAction);
+ return this;
+ }
+
+ /**
* Builds a new {@link FillResponse} instance.
*
* @throws IllegalStateException if any of the following conditions occur:
@@ -688,6 +716,10 @@ public final class FillResponse implements Parcelable {
if (mCancelIds != null) {
builder.append(", mCancelIds=").append(mCancelIds.length);
}
+ builder.append(", mSupportInlinePresentations=").append(mSupportsInlineSuggestions);
+ if (mInlineActions != null) {
+ builder.append(", mInlineActions=" + mInlineActions.getList());
+ }
return builder.append("]").toString();
}
@@ -717,6 +749,7 @@ public final class FillResponse implements Parcelable {
parcel.writeInt(mFlags);
parcel.writeIntArray(mCancelIds);
parcel.writeInt(mRequestId);
+ parcel.writeParcelable(mInlineActions, flags);
}
public static final @android.annotation.NonNull Parcelable.Creator<FillResponse> CREATOR =
@@ -771,6 +804,15 @@ public final class FillResponse implements Parcelable {
final int[] cancelIds = parcel.createIntArray();
builder.setPresentationCancelIds(cancelIds);
+ final ParceledListSlice<InlinePresentation> inlineActionsSlice = parcel.readParcelable(
+ null);
+ final List<InlinePresentation> inlineActions =
+ (inlineActionsSlice != null) ? inlineActionsSlice.getList() : null;
+ final int inlineActionsCount = (inlineActions != null) ? inlineActions.size() : 0;
+ for (int i = 0; i < inlineActionsCount; i++) {
+ builder.addInlineAction(inlineActions.get(i));
+ }
+
final FillResponse response = builder.build();
response.setRequestId(parcel.readInt());
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index 1568fb3af4c0..fb8406e99fa0 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -34,10 +34,22 @@ import com.android.internal.util.DataClass;
genEqualsHashCode = true)
public final class InlinePresentation implements Parcelable {
+
+ /**
+ * Represents the UI content and the action for the inline suggestion.
+ */
private final @NonNull Slice mSlice;
+ /**
+ * Specifies the UI specification for the inline suggestion.
+ */
private final @NonNull InlinePresentationSpec mInlinePresentationSpec;
+ /**
+ * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+ */
+ private final boolean mPinned;
+
// Code below generated by codegen v1.0.14.
@@ -53,30 +65,56 @@ public final class InlinePresentation implements Parcelable {
//@formatter:off
+ /**
+ * Creates a new InlinePresentation.
+ *
+ * @param slice
+ * Represents the UI content and the action for the inline suggestion.
+ * @param inlinePresentationSpec
+ * Specifies the UI specification for the inline suggestion.
+ * @param pinned
+ * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+ */
@DataClass.Generated.Member
public InlinePresentation(
@NonNull Slice slice,
- @NonNull InlinePresentationSpec inlinePresentationSpec) {
+ @NonNull InlinePresentationSpec inlinePresentationSpec,
+ boolean pinned) {
this.mSlice = slice;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mSlice);
this.mInlinePresentationSpec = inlinePresentationSpec;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mInlinePresentationSpec);
+ this.mPinned = pinned;
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * Represents the UI content and the action for the inline suggestion.
+ */
@DataClass.Generated.Member
public @NonNull Slice getSlice() {
return mSlice;
}
+ /**
+ * Specifies the UI specification for the inline suggestion.
+ */
@DataClass.Generated.Member
public @NonNull InlinePresentationSpec getInlinePresentationSpec() {
return mInlinePresentationSpec;
}
+ /**
+ * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+ */
+ @DataClass.Generated.Member
+ public boolean isPinned() {
+ return mPinned;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -85,7 +123,8 @@ public final class InlinePresentation implements Parcelable {
return "InlinePresentation { " +
"slice = " + mSlice + ", " +
- "inlinePresentationSpec = " + mInlinePresentationSpec +
+ "inlinePresentationSpec = " + mInlinePresentationSpec + ", " +
+ "pinned = " + mPinned +
" }";
}
@@ -103,7 +142,8 @@ public final class InlinePresentation implements Parcelable {
//noinspection PointlessBooleanExpression
return true
&& java.util.Objects.equals(mSlice, that.mSlice)
- && java.util.Objects.equals(mInlinePresentationSpec, that.mInlinePresentationSpec);
+ && java.util.Objects.equals(mInlinePresentationSpec, that.mInlinePresentationSpec)
+ && mPinned == that.mPinned;
}
@Override
@@ -115,6 +155,7 @@ public final class InlinePresentation implements Parcelable {
int _hash = 1;
_hash = 31 * _hash + java.util.Objects.hashCode(mSlice);
_hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentationSpec);
+ _hash = 31 * _hash + Boolean.hashCode(mPinned);
return _hash;
}
@@ -124,6 +165,9 @@ public final class InlinePresentation implements Parcelable {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
+ byte flg = 0;
+ if (mPinned) flg |= 0x4;
+ dest.writeByte(flg);
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mInlinePresentationSpec, flags);
}
@@ -139,6 +183,8 @@ public final class InlinePresentation implements Parcelable {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
+ byte flg = in.readByte();
+ boolean pinned = (flg & 0x4) != 0;
Slice slice = (Slice) in.readTypedObject(Slice.CREATOR);
InlinePresentationSpec inlinePresentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR);
@@ -148,6 +194,7 @@ public final class InlinePresentation implements Parcelable {
this.mInlinePresentationSpec = inlinePresentationSpec;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mInlinePresentationSpec);
+ this.mPinned = pinned;
// onConstructed(); // You can define this method to get a callback
}
@@ -167,10 +214,10 @@ public final class InlinePresentation implements Parcelable {
};
@DataClass.Generated(
- time = 1578081082387L,
+ time = 1579726472535L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java",
- inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 75f252e23f79..c21577842199 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -58,6 +58,7 @@ public abstract class DataLoaderService extends Service {
* Managed DataLoader interface. Each instance corresponds to a single installation session.
* @hide
*/
+ @SystemApi
public interface DataLoader {
/**
* A virtual constructor.
@@ -78,8 +79,8 @@ public abstract class DataLoaderService extends Service {
* @param removedFiles list of files removed in this installation session.
* @return false if unable to create and populate all addedFiles.
*/
- boolean onPrepareImage(Collection<InstallationFile> addedFiles,
- Collection<String> removedFiles);
+ boolean onPrepareImage(@NonNull Collection<InstallationFile> addedFiles,
+ @NonNull Collection<String> removedFiles);
}
/**
@@ -88,6 +89,7 @@ public abstract class DataLoaderService extends Service {
* @return An instance of a DataLoader.
* @hide
*/
+ @SystemApi
public @Nullable DataLoader onCreateDataLoader() {
return null;
}
@@ -188,6 +190,7 @@ public abstract class DataLoaderService extends Service {
*
* @hide
*/
+ @SystemApi
public static final class FileSystemConnector {
/**
* Create a wrapper for a native instance.
@@ -211,8 +214,8 @@ public abstract class DataLoaderService extends Service {
* @throws IOException if trouble opening the file for writing, such as lack of disk space
* or unavailable media.
*/
- public void writeData(String name, long offsetBytes, long lengthBytes,
- ParcelFileDescriptor incomingFd) throws IOException {
+ public void writeData(@NonNull String name, long offsetBytes, long lengthBytes,
+ @NonNull ParcelFileDescriptor incomingFd) throws IOException {
try {
nativeWriteData(mNativeInstance, name, offsetBytes, lengthBytes, incomingFd);
} catch (RuntimeException e) {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 0f339988ba3e..1966f17aaf35 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -29,7 +29,6 @@ import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.media.AudioFormat;
@@ -67,7 +66,12 @@ public class AlwaysOnHotwordDetector {
/**
* Indicates that recognition for the given keyphrase is not supported.
* No further interaction should be performed with the detector that returns this availability.
+ *
+ * @deprecated This is no longer a valid state. Enrollment can occur outside of
+ * {@link KeyphraseEnrollmentInfo} through another privileged application. We can no longer
+ * determine ahead of time if the keyphrase and locale are unsupported by the system.
*/
+ @Deprecated
public static final int STATE_KEYPHRASE_UNSUPPORTED = -1;
/**
* Indicates that the given keyphrase is not enrolled.
@@ -85,34 +89,6 @@ public class AlwaysOnHotwordDetector {
*/
private static final int STATE_NOT_READY = 0;
- // Keyphrase management actions. Used in getManageIntent() ----//
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "MANAGE_ACTION_" }, value = {
- MANAGE_ACTION_ENROLL,
- MANAGE_ACTION_RE_ENROLL,
- MANAGE_ACTION_UN_ENROLL
- })
- private @interface ManageActions {}
-
- /**
- * Indicates that we need to enroll.
- *
- * @hide
- */
- public static final int MANAGE_ACTION_ENROLL = 0;
- /**
- * Indicates that we need to re-enroll.
- *
- * @hide
- */
- public static final int MANAGE_ACTION_RE_ENROLL = 1;
- /**
- * Indicates that we need to un-enroll.
- *
- * @hide
- */
- public static final int MANAGE_ACTION_UN_ENROLL = 2;
-
//-- Flags for startRecognition ----//
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -248,7 +224,8 @@ public class AlwaysOnHotwordDetector {
* The metadata of the Keyphrase, derived from the enrollment application.
* This may be null if this keyphrase isn't supported by the enrollment application.
*/
- private final KeyphraseMetadata mKeyphraseMetadata;
+ @Nullable
+ private KeyphraseMetadata mKeyphraseMetadata;
private final KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
private final IVoiceInteractionService mVoiceInteractionService;
private final IVoiceInteractionManagerService mModelManagementService;
@@ -448,7 +425,6 @@ public class AlwaysOnHotwordDetector {
mText = text;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
- mKeyphraseMetadata = mKeyphraseEnrollmentInfo.getKeyphraseMetadata(text, locale);
mExternalCallback = callback;
mHandler = new MyHandler();
mInternalCallback = new SoundTriggerListener(mHandler);
@@ -484,8 +460,7 @@ public class AlwaysOnHotwordDetector {
}
// This method only makes sense if we can actually support a recognition.
- if (mAvailability != STATE_KEYPHRASE_ENROLLED
- && mAvailability != STATE_KEYPHRASE_UNENROLLED) {
+ if (mAvailability != STATE_KEYPHRASE_ENROLLED || mKeyphraseMetadata == null) {
throw new UnsupportedOperationException(
"Getting supported recognition modes for the keyphrase is not supported");
}
@@ -679,7 +654,7 @@ public class AlwaysOnHotwordDetector {
public Intent createEnrollIntent() {
if (DBG) Slog.d(TAG, "createEnrollIntent");
synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_ENROLL);
+ return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_ENROLL);
}
}
@@ -700,7 +675,7 @@ public class AlwaysOnHotwordDetector {
public Intent createUnEnrollIntent() {
if (DBG) Slog.d(TAG, "createUnEnrollIntent");
synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL);
+ return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_UN_ENROLL);
}
}
@@ -721,11 +696,11 @@ public class AlwaysOnHotwordDetector {
public Intent createReEnrollIntent() {
if (DBG) Slog.d(TAG, "createReEnrollIntent");
synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL);
+ return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_RE_ENROLL);
}
}
- private Intent getManageIntentLocked(int action) {
+ private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("getManageIntent called on an invalid detector");
}
@@ -761,8 +736,7 @@ public class AlwaysOnHotwordDetector {
void onSoundModelsChanged() {
synchronized (mLock) {
if (mAvailability == STATE_INVALID
- || mAvailability == STATE_HARDWARE_UNAVAILABLE
- || mAvailability == STATE_KEYPHRASE_UNSUPPORTED) {
+ || mAvailability == STATE_HARDWARE_UNAVAILABLE) {
Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config");
return;
}
@@ -772,7 +746,9 @@ public class AlwaysOnHotwordDetector {
// or was deleted.
// The availability change callback should ensure that the client starts recognition
// again if needed.
- stopRecognitionLocked();
+ if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
+ stopRecognitionLocked();
+ }
// Execute a refresh availability task - which should then notify of a change.
new RefreshAvailabiltyTask().execute();
@@ -955,20 +931,17 @@ public class AlwaysOnHotwordDetector {
@Override
public Void doInBackground(Void... params) {
int availability = internalGetInitialAvailability();
- boolean enrolled = false;
- // Fetch the sound model if the availability is one of the supported ones.
- if (availability == STATE_NOT_READY
- || availability == STATE_KEYPHRASE_UNENROLLED
- || availability == STATE_KEYPHRASE_ENROLLED) {
- enrolled = internalGetIsEnrolled(mKeyphraseMetadata.id, mLocale);
- if (!enrolled) {
- availability = STATE_KEYPHRASE_UNENROLLED;
- } else {
- availability = STATE_KEYPHRASE_ENROLLED;
- }
- }
synchronized (mLock) {
+ if (availability == STATE_NOT_READY) {
+ internalUpdateEnrolledKeyphraseMetadata();
+ if (mKeyphraseMetadata != null) {
+ availability = STATE_KEYPHRASE_ENROLLED;
+ } else {
+ availability = STATE_KEYPHRASE_UNENROLLED;
+ }
+ }
+
if (DBG) {
Slog.d(TAG, "Hotword availability changed from " + mAvailability
+ " -> " + availability);
@@ -997,28 +970,22 @@ public class AlwaysOnHotwordDetector {
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in getDspProperties!", e);
}
+
// No DSP available
if (dspModuleProperties == null) {
return STATE_HARDWARE_UNAVAILABLE;
}
- // No enrollment application supports this keyphrase/locale
- if (mKeyphraseMetadata == null) {
- return STATE_KEYPHRASE_UNSUPPORTED;
- }
+
return STATE_NOT_READY;
}
- /**
- * @return The corresponding {@link KeyphraseSoundModel} or null if none is found.
- */
- private boolean internalGetIsEnrolled(int keyphraseId, Locale locale) {
+ private void internalUpdateEnrolledKeyphraseMetadata() {
try {
- return mModelManagementService.isEnrolledForKeyphrase(
- mVoiceInteractionService, keyphraseId, locale.toLanguageTag());
+ mKeyphraseMetadata = mModelManagementService.getEnrolledKeyphraseMetadata(
+ mVoiceInteractionService, mText, mLocale.toLanguageTag());
} catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in listRegisteredKeyphraseSoundModels!", e);
+ Slog.w(TAG, "RemoteException in internalUpdateEnrolledKeyphraseMetadata", e);
}
- return false;
}
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 36e057f4a97d..fc99836b82fd 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -16,14 +16,18 @@
package android.service.voice;
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
+import android.media.voice.KeyphraseModelManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -304,6 +308,23 @@ public class VoiceInteractionService extends Service {
}
/**
+ * Creates an {@link KeyphraseModelManager} to use for enrolling voice models outside of the
+ * pre-bundled system voice models.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+ @NonNull
+ public final KeyphraseModelManager createKeyphraseModelManager() {
+ if (mSystemService == null) {
+ throw new IllegalStateException("Not available until onReady() is called");
+ }
+ synchronized (mLock) {
+ return new KeyphraseModelManager(mSystemService);
+ }
+ }
+
+ /**
* @return Details of keyphrases available for enrollment.
* @hide
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 52b72949ee04..36f2c6267622 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1137,7 +1137,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
mCallbacks, this, mDispatcherState,
WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
- mWindow.getWindow().setFitWindowInsetsTypes(0 /* types */);
+ mWindow.getWindow().getAttributes().setFitInsetsTypes(0 /* types */);
mWindow.getWindow().addFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 91691436a87a..dd78c78654c3 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -869,7 +869,7 @@ public abstract class WallpaperService extends Service {
// Add window
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
- mLayout.setFitWindowInsetsTypes(0 /* types */);
+ mLayout.setFitInsetsTypes(0 /* types */);
mLayout.setTitle(WallpaperService.this.getClass().getName());
mLayout.windowAnimations =
com.android.internal.R.style.Animation_Wallpaper;
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 57375919e6cd..6787c46c046e 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -36,6 +36,7 @@ import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.data.ApnSetting;
+import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.Log;
@@ -198,6 +199,25 @@ public class TelephonyRegistryManager {
}
/**
+ * Listen for incoming subscriptions
+ * @param subId Subscription ID
+ * @param pkg Package name
+ * @param featureId Feature ID
+ * @param listener Listener providing callback
+ * @param events Events
+ * @param notifyNow Whether to notify instantly
+ */
+ public void listenForSubscriber(int subId, @NonNull String pkg, @NonNull String featureId,
+ @NonNull PhoneStateListener listener, int events, boolean notifyNow) {
+ try {
+ sRegistry.listenForSubscriber(
+ subId, pkg, featureId, listener.callback, events, notifyNow);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Informs the system of an intentional upcoming carrier network change by a carrier app.
* This call only used to allow the system to provide alternative UI while telephony is
* performing an action that may result in intentional, temporary network lack of connectivity.
@@ -258,6 +278,32 @@ public class TelephonyRegistryManager {
}
/**
+ * Notify {@link SubscriptionInfo} change.
+ * @hide
+ */
+ @SystemApi
+ public void notifySubscriptionInfoChanged() {
+ try {
+ sRegistry.notifySubscriptionInfoChanged();
+ } catch (RemoteException ex) {
+ // system server crash
+ }
+ }
+
+ /**
+ * Notify opportunistic {@link SubscriptionInfo} change.
+ * @hide
+ */
+ @SystemApi
+ public void notifyOpportunisticSubscriptionInfoChanged() {
+ try {
+ sRegistry.notifyOpportunisticSubscriptionInfoChanged();
+ } catch (RemoteException ex) {
+ // system server crash
+ }
+ }
+
+ /**
* Notify {@link ServiceState} update on certain subscription.
*
* @param subId for which the service state changed.
@@ -394,6 +440,36 @@ public class TelephonyRegistryManager {
}
/**
+ * Notify outgoing emergency call.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param emergencyNumber Emergency number.
+ */
+ public void notifyOutgoingEmergencyCall(int phoneId, int subId,
+ @NonNull EmergencyNumber emergencyNumber) {
+ try {
+ sRegistry.notifyOutgoingEmergencyCall(phoneId, subId, emergencyNumber);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ /**
+ * Notify outgoing emergency SMS.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param emergencyNumber Emergency number.
+ */
+ public void notifyOutgoingEmergencySms(int phoneId, int subId,
+ @NonNull EmergencyNumber emergencyNumber) {
+ try {
+ sRegistry.notifyOutgoingEmergencySms(phoneId, subId, emergencyNumber);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ /**
* Notify radio power state changed on certain subscription.
*
* @param subId for which radio power state changed.
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index eb4af1c2a979..06fccaf8ea81 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -44,6 +44,9 @@ public class FeatureFlagUtils {
public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ =
"settings_notif_convo_bypass_shortcut_req";
+ /** @hide */
+ public static final String BACKUP_NO_KV_DATA_CHANGE_CALLS =
+ "backup_enable_no_data_notification_calls";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -62,6 +65,9 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
DEFAULT_FLAGS.put("settings_conditionals", "false");
DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+
+ // Disabled until backup transports support it.
+ DEFAULT_FLAGS.put(BACKUP_NO_KV_DATA_CHANGE_CALLS, "false");
}
/**
diff --git a/core/java/android/util/SparseSetArray.java b/core/java/android/util/SparseSetArray.java
index 9f0f24617f5d..f5025f7a9e99 100644
--- a/core/java/android/util/SparseSetArray.java
+++ b/core/java/android/util/SparseSetArray.java
@@ -37,10 +37,10 @@ public class SparseSetArray<T> {
mData.put(n, set);
}
if (set.contains(value)) {
- return true;
+ return false;
}
set.add(value);
- return false;
+ return true;
}
/**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 904c510a5b01..0304328f734a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -423,10 +423,14 @@ public final class Display {
/**
* Internal method to create a display.
* The display created with this method will have a static {@link DisplayAdjustments} applied.
- * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
- * or {@link android.hardware.display.DisplayManager#getDisplay}
- * to get a display object.
+ * Applications should use {@link android.content.Context#getDisplay} with
+ * {@link android.app.Activity} or a context associated with a {@link Display} via
+ * {@link android.content.Context#createDisplayContext(Display)}
+ * to get a display object associated with a {@link android.app.Context}, or
+ * {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id.
*
+ * @see android.content.Context#getDisplay()
+ * @see android.content.Context#createDisplayContext(Display)
* @hide
*/
public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo,
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 993bdc4d6543..d9c502e14e68 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -32,6 +32,7 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
+import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
@@ -111,6 +112,20 @@ interface IWindowManager
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void setEventDispatching(boolean enabled);
+
+ /** @return {@code true} if this binder is a registered window token. */
+ boolean isWindowToken(in IBinder binder);
+ /**
+ * Adds window token for a given type.
+ *
+ * @param token Token to be registered.
+ * @param type Window type to be used with this token.
+ * @param displayId The ID of the display where this token should be added.
+ * @param packageName The name of package to request to add window token.
+ * @return {@link WindowManagerGlobal#ADD_OKAY} if the addition was successful, an error code
+ * otherwise.
+ */
+ int addWindowContextToken(IBinder token, int type, int displayId, String packageName);
void addWindowToken(IBinder token, int type, int displayId);
void removeWindowToken(IBinder token, int displayId);
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
@@ -725,4 +740,12 @@ interface IWindowManager
* Called when a remote process modifies insets on a display window container.
*/
void modifyDisplayWindowInsets(int displayId, in InsetsState state);
+
+ /**
+ * Called to get the expected window insets.
+ * TODO(window-context): Remove when new insets flag is available.
+ */
+ void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
+ out Rect outContentInsets, out Rect outStableInsets,
+ out DisplayCutout.ParcelableWrapper displayCutout);
}
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 271566acb74e..8d58ee83cd67 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -45,12 +45,25 @@ public final class ImeFocusController {
mViewRootImpl = viewRootImpl;
}
+ @NonNull
private InputMethodManagerDelegate getImmDelegate() {
- if (mDelegate == null) {
- mDelegate = mViewRootImpl.mContext.getSystemService(
- InputMethodManager.class).getDelegate();
+ InputMethodManagerDelegate delegate = mDelegate;
+ if (delegate != null) {
+ return delegate;
}
- return mDelegate;
+ delegate = mViewRootImpl.mContext.getSystemService(InputMethodManager.class).getDelegate();
+ mDelegate = delegate;
+ return delegate;
+ }
+
+ /** Called when the view root is moved to a different display. */
+ @UiThread
+ void onMovedToDisplay() {
+ // InputMethodManager managed its instances for different displays. So if the associated
+ // display is changed, the delegate also needs to be refreshed (by getImmDelegate).
+ // See the comment in {@link android.app.SystemServiceRegistry} for InputMethodManager
+ // and {@link android.view.inputmethod.InputMethodManager#forContext}.
+ mDelegate = null;
}
@UiThread
@@ -103,7 +116,8 @@ public final class ImeFocusController {
}
boolean forceFocus = false;
- if (getImmDelegate().isRestartOnNextWindowFocus(true /* reset */)) {
+ final InputMethodManagerDelegate immDelegate = getImmDelegate();
+ if (immDelegate.isRestartOnNextWindowFocus(true /* reset */)) {
if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true");
forceFocus = true;
}
@@ -111,12 +125,13 @@ public final class ImeFocusController {
final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
onViewFocusChanged(viewForWindowFocus, true);
- getImmDelegate().startInputAsyncOnWindowFocusGain(viewForWindowFocus,
+ immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
}
public boolean checkFocus(boolean forceNewFocus, boolean startInput) {
- if (!getImmDelegate().isCurrentRootView(mViewRootImpl)
+ final InputMethodManagerDelegate immDelegate = getImmDelegate();
+ if (!immDelegate.isCurrentRootView(mViewRootImpl)
|| (mServedView == mNextServedView && !forceNewFocus)) {
return false;
}
@@ -128,15 +143,16 @@ public final class ImeFocusController {
// Close the connection when no next served view coming.
if (mNextServedView == null) {
- getImmDelegate().finishInput();
- getImmDelegate().closeCurrentIme();
+ immDelegate.finishInput();
+ immDelegate.closeCurrentIme();
return false;
}
mServedView = mNextServedView;
- getImmDelegate().finishComposingText();
+ immDelegate.finishComposingText();
if (startInput) {
- getImmDelegate().startInput(StartInputReason.CHECK_FOCUS, null, 0, 0, 0);
+ immDelegate.startInput(StartInputReason.CHECK_FOCUS, null /* focusedView */,
+ 0 /* startInputFlags */, 0 /* softInputMode */, 0 /* windowFlags */);
}
return true;
}
@@ -169,13 +185,14 @@ public final class ImeFocusController {
@UiThread
void onWindowDismissed() {
- if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) {
+ final InputMethodManagerDelegate immDelegate = getImmDelegate();
+ if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
return;
}
if (mServedView != null) {
- getImmDelegate().finishInput();
+ immDelegate.finishInput();
}
- getImmDelegate().setCurrentRootView(null);
+ immDelegate.setCurrentRootView(null);
mHasImeFocus = false;
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index f5afd106a4a7..405eccd56e3c 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -40,6 +40,7 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,8 +85,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
InsetsState state, WindowInsetsAnimationControlListener listener,
@InsetsType int types,
- InsetsAnimationControlCallbacks controller, long durationMs, boolean fade,
- @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
+ InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
+ boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
mControls = controls;
mListener = listener;
mTypes = types;
@@ -101,8 +102,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
mFrame = new Rect(frame);
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);
- mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes,
- InsetsController.INTERPOLATOR, durationMs);
+ mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes, interpolator,
+ durationMs);
mAnimation.setAlpha(getCurrentAlpha());
mController.startAnimation(this, listener, types, mAnimation,
new AnimationBounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation);
@@ -196,7 +197,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
state.getSource(control.getType()).setVisible(shown);
}
Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
- setInsetsAndAlpha(insets, 1f /* alpha */, shown ? 1f : 0f /* fraction */);
+ setInsetsAndAlpha(insets, 1f /* alpha */, 1f /* fraction */);
mFinished = true;
mShownOnFinish = shown;
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 411e910e1af1..c6e383539a82 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -28,6 +28,7 @@ import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -145,7 +146,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
controller.setInsetsAndAlpha(
value, 1f /* alpha */, (((DefaultAnimationControlListener)
((InsetsAnimationControlImpl) controller).getListener())
- .getRawProgress()));
+ .getRawFraction()));
}
}
@@ -204,9 +205,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mController.finish(mShow);
}
- protected float getRawProgress() {
- float fraction = (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
- return mShow ? fraction : 1 - fraction;
+ protected float getRawFraction() {
+ return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
}
protected long getDurationMs() {
@@ -437,27 +437,29 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@Override
public void controlWindowInsetsAnimation(@InsetsType int types, long durationMs,
- WindowInsetsAnimationControlListener listener) {
- controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs,
+ @Nullable Interpolator interpolator,
+ @NonNull WindowInsetsAnimationControlListener listener) {
+ controlWindowInsetsAnimation(types, listener, false /* fromIme */, durationMs, interpolator,
ANIMATION_TYPE_USER);
}
private void controlWindowInsetsAnimation(@InsetsType int types,
WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs,
- @AnimationType int animationType) {
+ @Nullable Interpolator interpolator, @AnimationType int animationType) {
// If the frame of our window doesn't span the entire display, the control API makes very
// little sense, as we don't deal with negative insets. So just cancel immediately.
if (!mState.getDisplayFrame().equals(mFrame)) {
listener.onCancelled();
return;
}
- controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, false /* fade */,
- animationType, getLayoutInsetsDuringAnimationMode(types));
+ controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
+ false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
}
private void controlAnimationUnchecked(@InsetsType int types,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
- long durationMs, boolean fade, @AnimationType int animationType,
+ long durationMs, Interpolator interpolator, boolean fade,
+ @AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
if (types == 0) {
// nothing to animate.
@@ -488,7 +490,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
- frame, mState, listener, typesReady, this, durationMs, fade,
+ frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
layoutInsetsDuringAnimation);
mRunningAnimations.add(new RunningAnimation(controller, animationType));
}
@@ -733,7 +735,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// and hidden state insets are correct.
controlAnimationUnchecked(
types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
- true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
+ INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 7707ad163b85..a6b7c33de3d9 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
@@ -88,6 +89,8 @@ public class Surface implements Parcelable {
private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
+ private static native int nativeSetFrameRate(long nativeObject, float frameRate);
+
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@Override
@@ -841,6 +844,34 @@ public class Surface implements Parcelable {
}
/**
+ * Sets the intended frame rate for this surface.
+ *
+ * On devices that are capable of running the display at different refresh rates, the
+ * system may choose a display refresh rate to better match this surface's frame
+ * rate. Usage of this API won't introduce frame rate throttling, or affect other
+ * aspects of the application's frame production pipeline. However, because the system
+ * may change the display refresh rate, calls to this function may result in changes
+ * to Choreographer callback timings, and changes to the time interval at which the
+ * system releases buffers back to the application.
+ *
+ * Note that this only has an effect for surfaces presented on the display. If this
+ * surface is consumed by something other than the system compositor, e.g. a media
+ * codec, this call has no effect.
+ *
+ * @param frameRate The intended frame rate of this surface. 0 is a special value that
+ * indicates the app will accept the system's choice for the display frame rate, which
+ * is the default behavior if this function isn't called. The frameRate param does
+ * *not* need to be a valid refresh rate for this device's display - e.g., it's fine
+ * to pass 30fps to a device that can only run the display at 60fps.
+ */
+ public void setFrameRate(@FloatRange(from = 0.0) float frameRate) {
+ int error = nativeSetFrameRate(mNativeObject, frameRate);
+ if (error != 0) {
+ throw new RuntimeException("Failed to set frame rate on Surface");
+ }
+ }
+
+ /**
* Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
* when a SurfaceTexture could not successfully be allocated.
*/
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bcc9e41b8ab0..f7b87cce7338 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -211,6 +211,9 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor,
@Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
+ private static native void nativeSetFrameRate(
+ long transactionObj, long nativeObject, float frameRate);
+
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
/**
@@ -2787,6 +2790,33 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Sets the intended frame rate for the surface {@link SurfaceControl}.
+ *
+ * On devices that are capable of running the display at different refresh rates, the system
+ * may choose a display refresh rate to better match this surface's frame rate. Usage of
+ * this API won't directly affect the application's frame production pipeline. However,
+ * because the system may change the display refresh rate, calls to this function may result
+ * in changes to Choreographer callback timings, and changes to the time interval at which
+ * the system releases buffers back to the application.
+ *
+ * @param sc The SurfaceControl to specify the frame rate of.
+ * @param frameRate The intended frame rate for this surface. 0 is a special value that
+ * indicates the app will accept the system's choice for the display frame
+ * rate, which is the default behavior if this function isn't called. The
+ * frameRate param does *not* need to be a valid refresh rate for this
+ * device's display - e.g., it's fine to pass 30fps to a device that can
+ * only run the display at 60fps.
+ * @return This transaction object.
+ */
+ @NonNull
+ public Transaction setFrameRate(
+ @NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate) {
+ checkPreconditions(sc);
+ nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate);
+ return this;
+ }
+
+ /**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
*
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 4f8aecd08f6d..71cf051a4e08 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -20,15 +20,21 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.Context;
+import android.graphics.PixelFormat;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
/**
- * Utility class for adding a view hierarchy to a SurfaceControl.
- *
- * See WindowlessWmTest for example usage.
- * @hide
+ * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
+ * will render in to a root SurfaceControl, and receive input based on the SurfaceControl's
+ * placement on-screen. The primary usage of this class is to embed a View hierarchy from
+ * one process in to another. After the SurfaceControlViewHost has been set up in the embedded
+ * content provider, we can send the {@link SurfaceControlViewHost.SurfacePackage}
+ * to the host process. The host process can then attach the hierarchy to a SurfaceView within
+ * its own by calling
+ * {@link SurfaceView#setChildSurfacePackage}.
*/
-@TestApi
public class SurfaceControlViewHost {
private ViewRootImpl mViewRoot;
private WindowlessWindowManager mWm;
@@ -36,20 +42,52 @@ public class SurfaceControlViewHost {
private SurfaceControl mSurfaceControl;
/**
- * @hide
+ * Package encapsulating a Surface hierarchy which contains interactive view
+ * elements. It's expected to get this object from
+ * {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within
+ * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}.
*/
- @TestApi
- public class SurfacePackage {
- final SurfaceControl mSurfaceControl;
+ public static final class SurfacePackage implements Parcelable {
+ private final SurfaceControl mSurfaceControl;
// TODO: Accessibility ID goes here
SurfacePackage(SurfaceControl sc) {
mSurfaceControl = sc;
}
+ private SurfacePackage(Parcel in) {
+ mSurfaceControl = new SurfaceControl();
+ mSurfaceControl.readFromParcel(in);
+ }
+
+ /**
+ * Use {@link SurfaceView#setChildSurfacePackage} or manually fix
+ * accessibility (see SurfaceView implementation).
+ * @hide
+ */
public @NonNull SurfaceControl getSurfaceControl() {
return mSurfaceControl;
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ mSurfaceControl.writeToParcel(out, flags);
+ }
+
+ public static final @NonNull Creator<SurfacePackage> CREATOR
+ = new Creator<SurfacePackage>() {
+ public SurfacePackage createFromParcel(Parcel in) {
+ return new SurfacePackage(in);
+ }
+ public SurfacePackage[] newArray(int size) {
+ return new SurfacePackage[size];
+ }
+ };
}
/** @hide */
@@ -59,17 +97,36 @@ public class SurfaceControlViewHost {
mViewRoot = new ViewRootImpl(c, d, mWm);
}
- public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
- @Nullable IBinder hostInputToken) {
+ /**
+ * Construct a new SurfaceControlViewHost. The root Surface will be
+ * allocated internally and is accessible via getSurfacePackage().
+ *
+ * The {@param hostToken} parameter, primarily used for ANR reporting,
+ * must be obtained from whomever will be hosting the embedded hierarchy.
+ * It's accessible from {@link SurfaceView#getHostToken}.
+ *
+ * @param context The Context object for your activity or application.
+ * @param display The Display the hierarchy will be placed on.
+ * @param hostToken The host token, as discussed above.
+ */
+ public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
+ @Nullable IBinder hostToken) {
mSurfaceControl = new SurfaceControl.Builder()
.setContainerLayer()
.setName("SurfaceControlViewHost")
.build();
- mWm = new WindowlessWindowManager(c.getResources().getConfiguration(), mSurfaceControl,
- hostInputToken);
- mViewRoot = new ViewRootImpl(c, d, mWm);
+ mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
+ mSurfaceControl, hostToken);
+ mViewRoot = new ViewRootImpl(context, display, mWm);
}
+ /**
+ * Return a SurfacePackage for the root SurfaceControl of the embedded hierarchy.
+ * Rather than be directly reparented using {@link SurfaceControl.Transaction} this
+ * SurfacePackage should be passed to {@link SurfaceView#setChildSurfacePackage}
+ * which will not only reparent the Surface, but ensure the accessibility hierarchies
+ * are linked.
+ */
public @Nullable SurfacePackage getSurfacePackage() {
if (mSurfaceControl != null) {
return new SurfacePackage(mSurfaceControl);
@@ -78,10 +135,32 @@ public class SurfaceControlViewHost {
}
}
- public void addView(View view, WindowManager.LayoutParams attrs) {
+ /**
+ * @hide
+ */
+ public void addView(@NonNull View view, WindowManager.LayoutParams attrs) {
mViewRoot.setView(view, attrs, null);
}
+ /**
+ * Set the root view of the SurfaceControlViewHost. This view will render in to
+ * the SurfaceControl, and receive input based on the SurfaceControls positioning on
+ * screen. It will be laid as if it were in a window of the passed in width and height.
+ *
+ * @param view The View to add
+ * @param width The width to layout the View within, in pixels.
+ * @param height The height to layout the View within, in pixels.
+ */
+ public void addView(@NonNull View view, int width, int height) {
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ addView(view, lp);
+ }
+
+ /**
+ * @hide
+ */
public void relayout(WindowManager.LayoutParams attrs) {
mViewRoot.setLayoutParams(attrs, false);
mViewRoot.setReportNextDraw();
@@ -90,8 +169,27 @@ public class SurfaceControlViewHost {
});
}
- public void dispose() {
+ /**
+ * Modify the size of the root view.
+ *
+ * @param width Width in pixels
+ * @param height Height in pixels
+ */
+ public void relayout(int width, int height) {
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ relayout(width, height);
+ }
+
+ /**
+ * Trigger the tear down of the embedded view hierarchy and release the SurfaceControl.
+ * This will result in onDispatchedFromWindow being dispatched to the embedded view hierarchy
+ * and render the object unusable.
+ */
+ public void release() {
mViewRoot.dispatchDetachedFromWindow();
+ mSurfaceControl.release();
}
/**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0de1a4f038ff..1981bdd93eeb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -20,6 +20,7 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLA
import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -43,6 +44,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceControl.Transaction;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.SurfaceControlViewHost;
import com.android.internal.view.SurfaceCallbackHelper;
@@ -204,6 +206,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
// The token of embedded windowless view hierarchy.
private IBinder mEmbeddedViewHierarchy;
+ SurfaceControlViewHost.SurfacePackage mSurfacePackage;
public SurfaceView(Context context) {
this(context, null);
@@ -877,6 +880,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
} else {
mTmpTransaction.hide(mSurfaceControl);
}
+
+ if (mSurfacePackage != null) {
+ reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
+ }
+
updateBackgroundVisibility(mTmpTransaction);
if (mUseAlpha) {
mTmpTransaction.setAlpha(mSurfaceControl, alpha);
@@ -1471,11 +1479,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
/**
- * @return The token used to identify the windows input channel.
- * @hide
+ * A token used for constructing {@link SurfaceControlViewHost}. This token should
+ * be passed from the host process to the client process.
+ *
+ * @return The token
*/
- @TestApi
- public @Nullable IBinder getInputToken() {
+ public @Nullable IBinder getHostToken() {
final ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot == null) {
return null;
@@ -1537,6 +1546,33 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
/**
+ * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
+ * within this SurfaceView. If this SurfaceView is above it's host Surface (see
+ * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
+ * input.
+ *
+ * @param p The SurfacePackage to embed.
+ */
+ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
+ final SurfaceControl sc = p != null ? p.getSurfaceControl() : null;
+ final SurfaceControl lastSc = mSurfacePackage != null ?
+ mSurfacePackage.getSurfaceControl() : null;
+ if (mSurfaceControl != null && lastSc != null) {
+ mTmpTransaction.reparent(lastSc, null).apply();
+ } else if (mSurfaceControl != null) {
+ reparentSurfacePackage(mTmpTransaction, p);
+ mTmpTransaction.apply();
+ }
+ mSurfacePackage = p;
+ }
+
+ private void reparentSurfacePackage(SurfaceControl.Transaction t,
+ SurfaceControlViewHost.SurfacePackage p) {
+ // TODO: Link accessibility IDs here.
+ t.reparent(p.getSurfaceControl(), mSurfaceControl);
+ }
+
+ /**
* Add the token of embedded view hierarchy. Set {@code null} to clear the embedded view
* hierarchy.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 377a7644f21b..c5f4faf2f462 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22,7 +22,10 @@ import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LO
import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
+import static android.view.WindowInsets.Type.ime;
+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 static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static java.lang.Math.max;
@@ -97,6 +100,7 @@ import android.util.FloatProperty;
import android.util.LayoutDirection;
import android.util.Log;
import android.util.LongSparseLongArray;
+import android.util.Pair;
import android.util.Pools.SynchronizedPool;
import android.util.Property;
import android.util.SparseArray;
@@ -110,9 +114,11 @@ import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Window.OnContentApplyWindowInsetsListener;
+import android.view.WindowInsets.Type;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
-import android.view.WindowInsetsAnimationCallback.DispatchMode;
+import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -140,6 +146,7 @@ import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable;
import com.android.internal.R;
+import com.android.internal.policy.DecorView;
import com.android.internal.view.TooltipPopup;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ScrollBarUtils;
@@ -1510,6 +1517,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate
* that they are optional and should be skipped if the window has
* requested system UI flags that ignore those insets for layout.
+ * <p>
+ * This is only used for support library as of Android R. The framework now uses
+ * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy
+ * insets path that loses insets information.
*/
static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800;
@@ -2258,7 +2269,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* be extended in the future to hold our own class with more than just
* a Rect. :)
*/
- static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
+ static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new);
/**
* Map used to store views' tags.
@@ -3420,6 +3431,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
* 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
* 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
+ * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
* |-------|-------|-------|-------|
*/
@@ -3457,6 +3469,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
| PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+ /**
+ * @see #OPTIONAL_FITS_SYSTEM_WINDOWS
+ */
+ static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -3506,7 +3523,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* requested the system UI (status bar) to be visible (the default).
*
* @see #setSystemUiVisibility(int)
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_VISIBLE = 0;
/**
@@ -3519,7 +3539,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <p>In low profile mode, the status bar and/or navigation icons may dim.
*
* @see #setSystemUiVisibility(int)
+ * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application
+ * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with
+ * {@link Type#systemBars()}.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001;
/**
@@ -3540,7 +3564,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* so that both elements reappear at the same time.
*
* @see #setSystemUiVisibility(int)
+ * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()}
+ * instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
/**
@@ -3576,7 +3603,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* the book.
*
* @see #setSystemUiVisibility(int)
+ * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()}
+ * instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
/**
@@ -3610,7 +3640,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
* Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the
* insets it adds to those given to the application.
+ *
+ * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve
+ * insets that don't change when system bars change visibility state.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;
/**
@@ -3622,6 +3656,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* decorations when they are shown. You can perform layout of your inner
* UI elements to account for the navigation system UI through the
* {@link #fitSystemWindows(Rect)} method.
+ *
+ * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
+ * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call
+ * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
+ * doesn't fit the navigation bar on the window content level.
*/
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
@@ -3646,7 +3685,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
* @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
* @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+ *
+ * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
+ * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call
+ * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
+ * doesn't fit the status bar on the window content level.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
/**
@@ -3656,7 +3701,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* user interaction.
* <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only
* has an effect when used in combination with that flag.</p>
+ *
+ * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_BARS_BY_SWIPE} instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;
/**
@@ -3674,7 +3722,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and
* {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination
* with one or both of those flags.</p>
+ *
+ * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
/**
@@ -3688,7 +3739,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* FLAG_TRANSLUCENT_STATUS}.
*
* @see android.R.attr#windowLightStatusBar
+ * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
/**
@@ -3714,7 +3767,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* FLAG_TRANSLUCENT_NAVIGATION}.
*
* @see android.R.attr#windowLightNavigationBar
+ * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead.
*/
+ @Deprecated
public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
/**
@@ -3942,7 +3997,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Flags that can impact the layout in relation to system UI.
+ *
+ * @deprecated System UI layout flags are deprecated.
*/
+ @Deprecated
public static final int SYSTEM_UI_LAYOUT_FLAGS =
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@@ -11020,23 +11078,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
- mUserPaddingStart = UNDEFINED_PADDING;
- mUserPaddingEnd = UNDEFINED_PADDING;
Rect localInsets = sThreadLocal.get();
- if (localInsets == null) {
- localInsets = new Rect();
- sThreadLocal.set(localInsets);
- }
boolean res = computeFitSystemWindows(insets, localInsets);
- mUserPaddingLeftInitial = localInsets.left;
- mUserPaddingRightInitial = localInsets.right;
- internalSetPadding(localInsets.left, localInsets.top,
- localInsets.right, localInsets.bottom);
+ applyInsets(localInsets);
return res;
}
return false;
}
+ private void applyInsets(Rect insets) {
+ mUserPaddingStart = UNDEFINED_PADDING;
+ mUserPaddingEnd = UNDEFINED_PADDING;
+ mUserPaddingLeftInitial = insets.left;
+ mUserPaddingRightInitial = insets.right;
+ internalSetPadding(insets.left, insets.top, insets.right, insets.bottom);
+ }
+
/**
* Called when the view should apply {@link WindowInsets} according to its internal policy.
*
@@ -11063,6 +11120,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The supplied insets with any applied insets consumed
*/
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) {
+ return onApplyFrameworkOptionalFitSystemWindows(insets);
+ }
if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
// We weren't called from within a direct call to fitSystemWindows,
// call into it as a fallback in case we're in a class that overrides it
@@ -11079,6 +11140,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return insets;
}
+ private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) {
+ Rect localInsets = sThreadLocal.get();
+ WindowInsets result = computeSystemWindowInsets(insets, localInsets);
+ applyInsets(localInsets);
+ return result;
+ }
+
/**
* Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
* window insets to this view. The listener's
@@ -11369,16 +11437,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return Insets that should be passed along to views under this one
*/
public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
- if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
- || mAttachInfo == null
- || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0)) {
+ boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0;
+ if (isOptionalFitSystemWindows && mAttachInfo != null) {
+ OnContentApplyWindowInsetsListener listener =
+ mAttachInfo.mContentOnApplyWindowInsetsListener;
+ if (listener == null) {
+ // The application wants to take care of fitting system window for
+ // the content.
+ outLocalInsets.setEmpty();
+ return in;
+ }
+ Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(in);
+ outLocalInsets.set(result.first.toRect());
+ return result.second;
+ } else {
outLocalInsets.set(in.getSystemWindowInsetsAsRect());
return in.consumeSystemWindowInsets().inset(outLocalInsets);
- } else {
- // The application wants to take care of fitting system window for
- // the content.
- outLocalInsets.setEmpty();
- return in;
}
}
@@ -11449,7 +11524,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * For use by PhoneWindow to make its own system window fitting optional.
+ * @see #OPTIONAL_FITS_SYSTEM_WINDOWS
* @hide
*/
@UnsupportedAppUsage
@@ -11458,6 +11533,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @see #PFLAG4_OPTIONAL_FITS_SYSTEM_WINDOWS
+ * @hide
+ */
+ public void makeFrameworkOptionalFitsSystemWindows() {
+ mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS;
+ }
+
+ /**
* Returns the visibility status for this view.
*
* @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -25743,7 +25826,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
* {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
* and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}.
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public void setSystemUiVisibility(int visibility) {
if (visibility != mSystemUiVisibility) {
mSystemUiVisibility = visibility;
@@ -25760,7 +25847,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
* {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
* and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}.
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public int getSystemUiVisibility() {
return mSystemUiVisibility;
}
@@ -25770,7 +25861,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* the entire window. This is the combination of the
* {@link #setSystemUiVisibility(int)} values supplied by all of the
* views in the window.
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public int getWindowSystemUiVisibility() {
return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0;
}
@@ -25782,14 +25877,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)}
* in that this is only telling you about the local request of the window,
* not the actual values applied by the system.
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public void onWindowSystemUiVisibilityChanged(int visible) {
}
/**
* Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down
* the view hierarchy.
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public void dispatchWindowSystemUiVisiblityChanged(int visible) {
onWindowSystemUiVisibilityChanged(visible);
}
@@ -25797,7 +25900,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Set a listener to receive callbacks when the visibility of the system bar changes.
* @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks.
+ *
+ * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities
+ * by setting a {@link OnApplyWindowInsetsListener} on this view.
*/
+ @Deprecated
public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {
getListenerInfo().mOnSystemUiVisibilityChangeListener = l;
if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
@@ -25808,7 +25915,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down
* the view hierarchy.
+ *
+ * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities
+ * by setting a {@link OnApplyWindowInsetsListener} on this view.
*/
+ @Deprecated
public void dispatchSystemUiVisibilityChanged(int visibility) {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
@@ -28249,7 +28360,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* state, not what the application is requesting.
*
* @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
+ *
+ * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities
+ * by setting a {@link OnApplyWindowInsetsListener} on this view.
*/
+ @Deprecated
public interface OnSystemUiVisibilityChangeListener {
/**
* Called when the status bar changes visibility because of a call to
@@ -28415,6 +28530,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* window.
*/
final static class AttachInfo {
+
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -28854,6 +28970,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
ContentCaptureManager mContentCaptureManager;
/**
+ * Listener used to fit content on window level.
+ */
+ OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e6470a7d1e27..4f03ca152850 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -55,6 +55,7 @@ import android.util.Pools;
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.DispatchMode;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
@@ -1527,6 +1528,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public void makeFrameworkOptionalFitsSystemWindows() {
+ super.makeFrameworkOptionalFitsSystemWindows();
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].makeFrameworkOptionalFitsSystemWindows();
+ }
+ }
+
@Override
public void dispatchDisplayHint(int hint) {
super.dispatchDisplayHint(hint);
@@ -1871,6 +1885,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
+ @Deprecated
public void dispatchWindowSystemUiVisiblityChanged(int visible) {
super.dispatchWindowSystemUiVisiblityChanged(visible);
@@ -1883,6 +1898,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
+ @Deprecated
public void dispatchSystemUiVisibilityChanged(int visible) {
super.dispatchSystemUiVisibilityChanged(visible);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 09ebd005e7ed..f5cfbec924ac 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -122,6 +122,7 @@ import android.view.SurfaceControl.Transaction;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
+import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -755,6 +756,11 @@ public final class ViewRootImpl implements ViewParent,
mActivityConfigCallback = callback;
}
+ public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
+ requestFitSystemWindows();
+ }
+
public void addWindowCallbacks(WindowCallbacks callback) {
synchronized (mWindowCallbacks) {
mWindowCallbacks.add(callback);
@@ -1442,6 +1448,7 @@ public final class ViewRootImpl implements ViewParent,
// Get new instance of display based on current display adjustments. It may be updated later
// if moving between the displays also involved a configuration change.
updateInternalDisplay(displayId, mView.getResources());
+ mImeFocusController.onMovedToDisplay();
mAttachInfo.mDisplayState = mDisplay.getState();
// Internal state updated, now notify the view hierarchy.
mView.dispatchMovedToDisplay(mDisplay, config);
@@ -1978,9 +1985,9 @@ public final class ViewRootImpl implements ViewParent,
return;
}
- int types = inOutParams.getFitWindowInsetsTypes();
- int sides = inOutParams.getFitWindowInsetsSides();
- boolean ignoreVis = inOutParams.getFitIgnoreVisibility();
+ int types = inOutParams.getFitInsetsTypes();
+ int sides = inOutParams.getFitInsetsSides();
+ boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility();
if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0
|| (flags & FLAG_LAYOUT_IN_SCREEN) != 0)
@@ -1997,9 +2004,9 @@ public final class ViewRootImpl implements ViewParent,
&& adjust == SOFT_INPUT_ADJUST_RESIZE) {
types |= Type.ime();
}
- inOutParams.setFitWindowInsetsTypes(types);
- inOutParams.setFitWindowInsetsSides(sides);
- inOutParams.setFitIgnoreVisibility(ignoreVis);
+ inOutParams.setFitInsetsTypes(types);
+ inOutParams.setFitInsetsSides(sides);
+ inOutParams.setFitInsetsIgnoringVisibility(ignoreVis);
// The fitting of insets are not really controlled by the clients, so we remove the flag.
inOutParams.privateFlags &= ~PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a1894f30d6f6..0ef4e338f81c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -33,6 +33,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -46,6 +47,9 @@ import android.os.RemoteException;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionManager;
+import android.util.Pair;
+import android.view.View.OnApplyWindowInsetsListener;
+import android.view.ViewGroup.LayoutParams;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityEvent;
@@ -692,6 +696,32 @@ public abstract class Window {
int dropCountSinceLastInvocation);
}
+ /**
+ * Listener for applying window insets on the content of a window in a custom way.
+ *
+ * <p>Apps may choose to implement this interface if they want to apply custom policy
+ * to the way that window insets are treated for fitting root-level content views.
+ *
+ * @see Window#setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener)
+ */
+ public interface OnContentApplyWindowInsetsListener {
+
+ /**
+ * Called when the window needs to apply insets on the container of its content view which
+ * are set by calling {@link #setContentView}. The method should determine what insets to
+ * apply on the container of the root level content view and what should be dispatched to
+ * the content view's
+ * {@link View#setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener)} through the view
+ * hierarchy.
+ *
+ * @param insets The root level insets that are about to be dispatched
+ * @return A pair, with the first element containing the insets to apply as margin to the
+ * root-level content views, and the second element determining what should be
+ * dispatched to the content view.
+ */
+ @NonNull Pair<Insets, WindowInsets> onContentApplyWindowInsets(
+ @NonNull WindowInsets insets);
+ }
public Window(Context context) {
mContext = context;
@@ -1281,57 +1311,33 @@ public abstract class Window {
}
/**
- * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsTypes(int)}
- * @hide pending unhide
- */
- public void setFitWindowInsetsTypes(@InsetsType int types) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitWindowInsetsTypes(types);
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsSides(int)}
- * @hide pending unhide
- */
- public void setFitWindowInsetsSides(@InsetsSide int sides) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitWindowInsetsSides(sides);
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#setFitIgnoreVisibility(boolean)}
- * @hide pending unhide
- */
- public void setFitIgnoreVisibility(boolean ignore) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitIgnoreVisibility(ignore);
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsTypes}
- * @hide pending unhide
- */
- public @InsetsType int getFitWindowInsetsTypes() {
- return getAttributes().getFitWindowInsetsTypes();
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsSides()}
- * @hide pending unhide
+ * Sets the listener to be invoked when fitting root-level content views.
+ * <p>
+ * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
+ * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
+ * fits content according to these flags.
+ * </p>
+ * @param contentOnApplyWindowInsetsListener The listener to use for fitting root-level content
+ * views, or {@code null} to disable any kind of
+ * content fitting on the window level and letting the
+ * {@link WindowInsets} pass through to the content
+ * view.
+ * @see OnContentApplyWindowInsetsListener
*/
- public @InsetsSide int getFitWindowInsetsSides() {
- return getAttributes().getFitWindowInsetsSides();
+ public void setOnContentApplyWindowInsetsListener(
+ @Nullable OnContentApplyWindowInsetsListener contentOnApplyWindowInsetsListener) {
}
/**
- * A shortcut for {@link WindowManager.LayoutParams#getFitIgnoreVisibility()}
- * @hide pending unhide
+ * Resets the listener set via {@link #setOnContentApplyWindowInsetsListener} to the default
+ * state.
+ * <p>
+ * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
+ * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
+ * fits content according to these flags.
+ * </p>
*/
- public boolean getFitIgnoreVisibility() {
- return getAttributes().getFitIgnoreVisibility();
+ public void resetOnContentApplyWindowInsetsListener() {
}
/**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 0a2a45b44523..a6c311e1daa5 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -301,11 +301,14 @@ public final class WindowInsets {
* </p>
*
* @return The system window insets
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
@NonNull
public Insets getSystemWindowInsets() {
Insets result = mCompatIgnoreVisibility
- ? getMaxInsets(mCompatInsetTypes & ~ime())
+ ? getInsetsIgnoringVisibility(mCompatInsetTypes & ~ime())
: getInsets(mCompatInsetTypes);
// We can't query max insets for IME, so we need to add it manually after.
@@ -328,25 +331,26 @@ public final class WindowInsets {
}
/**
- * Returns the maximum amount of insets a specific set of windows can cause, denoted by the
- * {@code typeMask} bit mask of {@link InsetsType}s.
+ * Returns the insets a specific set of windows can cause, denoted by the
+ * {@code typeMask} bit mask of {@link InsetsType}s, regardless of whether that type is
+ * currently visible or not.
*
- * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
+ * <p>The insets represents the area of a a window that that <b>may</b> be partially
* or fully obscured by the system window identified by {@code type}. This value does not
- * change based on the visibility state of those elements. for example, if the status bar is
- * normally shown, but temporarily hidden, the maximum inset will still provide the inset
+ * change based on the visibility state of those elements. For example, if the status bar is
+ * normally shown, but temporarily hidden, the inset returned here will still provide the inset
* associated with the status bar being shown.</p>
*
* @param typeMask Bit mask of {@link InsetsType}s to query the insets for.
* @return The insets.
*
- * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum
- * insets are not available for this type as the height of the
+ * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Insets are
+ * not available if the IME isn't visible as the height of the
* IME is dynamic depending on the {@link EditorInfo} of the
* currently focused view, as well as the UI state of the IME.
*/
@NonNull
- public Insets getMaxInsets(@InsetsType int typeMask) throws IllegalArgumentException {
+ public Insets getInsetsIgnoringVisibility(@InsetsType int typeMask) {
if ((typeMask & IME) != 0) {
throw new IllegalArgumentException("Unable to query the maximum insets for IME");
}
@@ -381,7 +385,10 @@ public final class WindowInsets {
* </p>
*
* @return The left system window inset
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getSystemWindowInsetLeft() {
return getSystemWindowInsets().left;
}
@@ -394,7 +401,10 @@ public final class WindowInsets {
* </p>
*
* @return The top system window inset
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getSystemWindowInsetTop() {
return getSystemWindowInsets().top;
}
@@ -407,7 +417,10 @@ public final class WindowInsets {
* </p>
*
* @return The right system window inset
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getSystemWindowInsetRight() {
return getSystemWindowInsets().right;
}
@@ -420,7 +433,10 @@ public final class WindowInsets {
* </p>
*
* @return The bottom system window inset
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getSystemWindowInsetBottom() {
return getSystemWindowInsets().bottom;
}
@@ -433,7 +449,10 @@ public final class WindowInsets {
* </p>
*
* @return true if any of the system window inset values are nonzero
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public boolean hasSystemWindowInsets() {
return !getSystemWindowInsets().equals(Insets.NONE);
}
@@ -594,7 +613,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return The stable insets
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
@NonNull
public Insets getStableInsets() {
return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
@@ -610,7 +632,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return The top stable inset
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getStableInsetTop() {
return getStableInsets().top;
}
@@ -625,7 +650,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return The left stable inset
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getStableInsetLeft() {
return getStableInsets().left;
}
@@ -640,7 +668,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return The right stable inset
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getStableInsetRight() {
return getStableInsets().right;
}
@@ -655,7 +686,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return The bottom stable inset
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public int getStableInsetBottom() {
return getStableInsets().bottom;
}
@@ -670,7 +704,10 @@ public final class WindowInsets {
* associated with the status bar being shown.</p>
*
* @return true if any of the stable inset values are nonzero
+ * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
+ * instead.
*/
+ @Deprecated
public boolean hasStableInsets() {
return !getStableInsets().equals(Insets.NONE);
}
@@ -706,7 +743,9 @@ public final class WindowInsets {
* system window insets} by {@link #consumeSystemWindowInsets()}.
*
* @see #getMandatorySystemGestureInsets
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#systemGestures()} instead.
*/
+ @Deprecated
@NonNull
public Insets getSystemGestureInsets() {
return getInsets(mTypeInsetsMap, SYSTEM_GESTURES);
@@ -734,7 +773,9 @@ public final class WindowInsets {
* system window insets} by {@link #consumeSystemWindowInsets()}.
*
* @see #getSystemGestureInsets
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#mandatorySystemGestures()} instead.
*/
+ @Deprecated
@NonNull
public Insets getMandatorySystemGestureInsets() {
return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
@@ -760,7 +801,10 @@ public final class WindowInsets {
*
* <p>This inset is consumed together with the {@link #getSystemWindowInsets()
* system window insets} by {@link #consumeSystemWindowInsets()}.
+ *
+ * @deprecated Use {@link #getInsets(int)} with {@link Type#tappableElement()} instead.
*/
+ @Deprecated
@NonNull
public Insets getTappableElementInsets() {
return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
@@ -985,7 +1029,9 @@ public final class WindowInsets {
*
* @see #getSystemWindowInsets()
* @return itself
+ * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#systemBars()}.
*/
+ @Deprecated
@NonNull
public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
Preconditions.checkNotNull(systemWindowInsets);
@@ -1003,7 +1049,9 @@ public final class WindowInsets {
*
* @see #getSystemGestureInsets()
* @return itself
+ * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#systemGestures()}.
*/
+ @Deprecated
@NonNull
public Builder setSystemGestureInsets(@NonNull Insets insets) {
WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets);
@@ -1023,7 +1071,10 @@ public final class WindowInsets {
*
* @see #getMandatorySystemGestureInsets()
* @return itself
+ * @deprecated Use {@link #setInsets(int, Insets)} with
+ * {@link Type#mandatorySystemGestures()}.
*/
+ @Deprecated
@NonNull
public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
@@ -1038,7 +1089,9 @@ public final class WindowInsets {
*
* @see #getTappableElementInsets()
* @return itself
+ * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#tappableElement()}.
*/
+ @Deprecated
@NonNull
public Builder setTappableElementInsets(@NonNull Insets insets) {
WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
@@ -1068,15 +1121,15 @@ public final class WindowInsets {
}
/**
- * Sets the maximum amount of insets a specific window type in pixels.
+ * Sets the insets a specific window type in pixels, while ignoring its visibility state.
*
- * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
- * or fully obscured by the system windows identified by {@code typeMask}. This value does
- * not change based on the visibility state of those elements. for example, if the status
- * bar is normally shown, but temporarily hidden, the maximum inset will still provide the
+ * <p>The insets represents the area of a a window that that <b>may</b> be partially
+ * or fully obscured by the system window identified by {@code type}. This value does not
+ * change based on the visibility state of those elements. For example, if the status bar is
+ * normally shown, but temporarily hidden, the inset returned here will still provide the
* inset associated with the status bar being shown.</p>
*
- * @see #getMaxInsets(int)
+ * @see #getInsetsIgnoringVisibility(int)
*
* @param typeMask The bitmask of {@link InsetsType} to set the insets for.
* @param insets The insets to set.
@@ -1090,7 +1143,7 @@ public final class WindowInsets {
* state of the IME.
*/
@NonNull
- public Builder setMaxInsets(@InsetsType int typeMask, @NonNull Insets insets)
+ public Builder setInsetsIgnoringVisibility(@InsetsType int typeMask, @NonNull Insets insets)
throws IllegalArgumentException{
if (typeMask == IME) {
throw new IllegalArgumentException("Maximum inset not available for IME");
@@ -1134,7 +1187,10 @@ public final class WindowInsets {
*
* @see #getStableInsets()
* @return itself
+ * @deprecated Use {@link #setInsetsIgnoringVisibility(int, Insets)} with
+ * {@link Type#systemBars()}.
*/
+ @Deprecated
@NonNull
public Builder setStableInsets(@NonNull Insets stableInsets) {
Preconditions.checkNotNull(stableInsets);
@@ -1267,13 +1323,6 @@ public final class WindowInsets {
}
/**
- * @return An insets type representing decor that is being app-controlled.
- */
- public static @InsetsType int windowDecor() {
- return WINDOW_DECOR;
- }
-
- /**
* Returns an insets type representing the system gesture insets.
*
* <p>The system gesture insets represent the area of a window where system gestures have
@@ -1309,18 +1358,17 @@ public final class WindowInsets {
}
/**
- * @return All system bars. Includes {@link #statusBars()} as well as
+ * @return All system bars. Includes {@link #statusBars()}, {@link #captionBar()} as well as
* {@link #navigationBars()}, but not {@link #ime()}.
*/
public static @InsetsType int systemBars() {
- return STATUS_BARS | NAVIGATION_BARS;
+ return STATUS_BARS | NAVIGATION_BARS | CAPTION_BAR;
}
/**
* @return All inset types combined.
*
- * TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
- * {@link #ime()} does not seem very useful.
+ * @hide
*/
public static @InsetsType int all() {
return 0xFFFFFFFF;
@@ -1340,7 +1388,6 @@ public final class WindowInsets {
/**
* Class that defines different sides for insets.
- * @hide pending unhide
*/
public static final class Side {
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
index 53d493985b32..1e04d02fcb80 100644
--- a/core/java/android/view/WindowInsetsAnimationCallback.java
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -88,7 +88,7 @@ public interface WindowInsetsAnimationCallback {
* <ul>
* <li>Application calls {@link WindowInsetsController#hideInputMethod()},
* {@link WindowInsetsController#showInputMethod()},
- * {@link WindowInsetsController#controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)}</li>
+ * {@link WindowInsetsController#controlInputMethodAnimation}</li>
* <li>onPrepare is called on the view hierarchy listeners</li>
* <li>{@link View#onApplyWindowInsets} will be called with the end state of the
* animation</li>
@@ -182,14 +182,26 @@ public interface WindowInsetsAnimationCallback {
private final @InsetsType int mTypeMask;
private float mFraction;
@Nullable private final Interpolator mInterpolator;
- private long mDurationMs;
+ private final long mDurationMillis;
private float mAlpha;
+ /**
+ * Creates a new {@link InsetsAnimation} object.
+ * <p>
+ * This should only be used for testing, as usually the system creates this object for the
+ * application to listen to with {@link WindowInsetsAnimationCallback}.
+ * </p>
+ * @param typeMask The bitmask of {@link WindowInsets.Type}s that are animating.
+ * @param interpolator The interpolator of the animation.
+ * @param durationMillis The duration of the animation in
+ * {@link java.util.concurrent.TimeUnit#MILLISECONDS}.
+ */
public InsetsAnimation(
- @InsetsType int typeMask, @Nullable Interpolator interpolator, long durationMs) {
+ @InsetsType int typeMask, @Nullable Interpolator interpolator,
+ long durationMillis) {
mTypeMask = typeMask;
mInterpolator = interpolator;
- mDurationMs = durationMs;
+ mDurationMillis = durationMillis;
}
/**
@@ -201,14 +213,18 @@ public interface WindowInsetsAnimationCallback {
/**
* Returns the raw fractional progress of this animation between
- * {@link AnimationBounds#getLowerBound()} and {@link AnimationBounds#getUpperBound()}. Note
+ * start state of the animation and the end state of the animation. Note
* that this progress is the global progress of the animation, whereas
* {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may
* be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
* Progress per insets animation is global for the entire animation. One animation animates
* all things together (in, out, ...). If they don't animate together, we'd have
* multiple animations.
- *
+ * <p>
+ * Note: In case the application is controlling the animation, the valued returned here will
+ * be the same as the application passed into
+ * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
+ * </p>
* @return The current progress of this animation.
*/
@FloatRange(from = 0f, to = 1f)
@@ -218,16 +234,27 @@ public interface WindowInsetsAnimationCallback {
/**
* Returns the interpolated fractional progress of this animation between
- * {@link AnimationBounds#getLowerBound()} and {@link AnimationBounds#getUpperBound()}. Note
+ * start state of the animation and the end state of the animation. Note
* that this progress is the global progress of the animation, whereas
* {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may
* be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
* Progress per insets animation is global for the entire animation. One animation animates
* all things together (in, out, ...). If they don't animate together, we'd have
* multiple animations.
+ * <p>
+ * Note: In case the application is controlling the animation, the valued returned here will
+ * be the same as the application passed into
+ * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)},
+ * interpolated with the interpolator passed into
+ * {@link WindowInsetsController#controlInputMethodAnimation}.
+ * </p>
+ * <p>
+ * Note: For system-initiated animations, this will always return a valid value between 0
+ * and 1.
+ * </p>
* @see #getFraction() for raw fraction.
* @return The current interpolated progress of this animation. -1 if interpolator isn't
- * specified.
+ * specified.
*/
public float getInterpolatedFraction() {
if (mInterpolator != null) {
@@ -236,52 +263,66 @@ public interface WindowInsetsAnimationCallback {
return -1;
}
+ /**
+ * Retrieves the interpolator used for this animation, or {@code null} if this animation
+ * doesn't follow an interpolation curved. For system-initiated animations, this will never
+ * return {@code null}.
+ *
+ * @return The interpolator used for this animation.
+ */
@Nullable
public Interpolator getInterpolator() {
return mInterpolator;
}
/**
- * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}.
+ * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or
+ * -1 if the animation doesn't have a fixed duration.
*/
public long getDurationMillis() {
- return mDurationMs;
+ return mDurationMillis;
}
/**
* Set fraction of the progress if {@link WindowInsets.Type.InsetsType} animation is
- * controlled by the app {@see #getCurrentFraction}.
- * <p>Note: If app didn't create {@link InsetsAnimation}, it shouldn't set progress either.
- * Progress would be set by system with the system-default animation.
+ * controlled by the app.
+ * <p>
+ * Note: This should only be used for testing, as the system fills in the fraction for the
+ * application or the fraction that was passed into
+ * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being
+ * used.
* </p>
* @param fraction fractional progress between 0 and 1 where 0 represents hidden and
* zero progress and 1 represent fully shown final state.
+ * @see #getFraction()
*/
public void setFraction(@FloatRange(from = 0f, to = 1f) float fraction) {
mFraction = fraction;
}
/**
- * Set duration of the animation if {@link WindowInsets.Type.InsetsType} animation is
- * controlled by the app.
- * <p>Note: If app didn't create {@link InsetsAnimation}, it shouldn't set duration either.
- * Duration would be set by system with the system-default animation.
- * </p>
- * @param durationMs in {@link java.util.concurrent.TimeUnit#MILLISECONDS}
- */
- public void setDuration(long durationMs) {
- mDurationMs = durationMs;
- }
-
- /**
- * @return alpha of {@link WindowInsets.Type.InsetsType}.
+ * Retrieves the translucency of the windows that are animating.
+ *
+ * @return Alpha of windows that cause insets of type {@link WindowInsets.Type.InsetsType}.
*/
@FloatRange(from = 0f, to = 1f)
public float getAlpha() {
return mAlpha;
}
- void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) {
+ /**
+ * Sets the translucency of the windows that are animating.
+ * <p>
+ * Note: This should only be used for testing, as the system fills in the alpha for the
+ * application or the alpha that was passed into
+ * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being
+ * used.
+ * </p>
+ * @param alpha Alpha of windows that cause insets of type
+ * {@link WindowInsets.Type.InsetsType}.
+ * @see #getAlpha()
+ */
+ public void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) {
mAlpha = alpha;
}
}
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index f292ca4facbf..02323cfb4f00 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -20,8 +20,11 @@ import static android.view.WindowInsets.Type.ime;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Insets;
import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
+import android.view.animation.Interpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -79,7 +82,6 @@ public interface WindowInsetsController {
* shown on any user interaction on the corresponding display if navigation bars are hidden by
* {@link #hide(int)} or
* {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
- * @hide
*/
int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0;
@@ -90,7 +92,6 @@ public interface WindowInsetsController {
*
* <p>When system bars are hidden in this mode, they can be revealed with system gestures, such
* as swiping from the edge of the screen where the bar is hidden from.</p>
- * @hide
*/
int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1;
@@ -103,7 +104,6 @@ public interface WindowInsetsController {
* gestures, such as swiping from the edge of the screen where the bar is hidden from. These
* transient system bars will overlay app’s content, may have some degree of transparency, and
* will automatically hide after a short timeout.</p>
- * @hide
*/
int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2;
@@ -126,7 +126,6 @@ public interface WindowInsetsController {
*
* @param types A bitmask of {@link InsetsType} specifying what windows the app
* would like to make appear on screen.
- * @hide
*/
void show(@InsetsType int types);
@@ -139,7 +138,6 @@ public interface WindowInsetsController {
*
* @param types A bitmask of {@link InsetsType} specifying what windows the app
* would like to make disappear.
- * @hide
*/
void hide(@InsetsType int types);
@@ -148,29 +146,50 @@ public interface WindowInsetsController {
* the position of the windows in the system causing insets directly.
*
* @param types The {@link InsetsType}s the application has requested to control.
- * @param durationMillis duration of animation in
+ * @param durationMillis Duration of animation in
* {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
- * animation doesn't have a predetermined duration.
+ * animation doesn't have a predetermined duration.T his value will be
+ * passed to {@link InsetsAnimation#getDurationMillis()}
+ * @param interpolator The interpolator used for this animation, or {@code null} if this
+ * animation doesn't follow an interpolation curve. This value will be
+ * passed to {@link InsetsAnimation#getInterpolator()} and used to calculate
+ * {@link InsetsAnimation#getInterpolatedFraction()}.
* @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
* windows are ready to be controlled, among other callbacks.
- * @hide
+ *
+ * @see InsetsAnimation#getFraction()
+ * @see InsetsAnimation#getInterpolatedFraction()
+ * @see InsetsAnimation#getInterpolator()
+ * @see InsetsAnimation#getDurationMillis()
*/
void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
+ @Nullable Interpolator interpolator,
@NonNull WindowInsetsAnimationControlListener listener);
/**
* Lets the application control the animation for showing the IME in a frame-by-frame manner by
* modifying the position of the IME when it's causing insets.
*
- * @param durationMillis duration of the animation in
+ * @param durationMillis Duration of the animation in
* {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
- * animation doesn't have a predetermined duration.
+ * animation doesn't have a predetermined duration. This value will be
+ * passed to {@link InsetsAnimation#getDurationMillis()}
+ * @param interpolator The interpolator used for this animation, or {@code null} if this
+ * animation doesn't follow an interpolation curve. This value will be
+ * passed to {@link InsetsAnimation#getInterpolator()} and used to calculate
+ * {@link InsetsAnimation#getInterpolatedFraction()}.
* @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
* IME are ready to be controlled, among other callbacks.
+ *
+ * @see InsetsAnimation#getFraction()
+ * @see InsetsAnimation#getInterpolatedFraction()
+ * @see InsetsAnimation#getInterpolator()
+ * @see InsetsAnimation#getDurationMillis()
*/
default void controlInputMethodAnimation(long durationMillis,
+ @Nullable Interpolator interpolator,
@NonNull WindowInsetsAnimationControlListener listener) {
- controlWindowInsetsAnimation(ime(), durationMillis, listener);
+ controlWindowInsetsAnimation(ime(), durationMillis, interpolator, listener);
}
/**
@@ -181,7 +200,7 @@ public interface WindowInsetsController {
* the event by observing {@link View#onApplyWindowInsets} and checking visibility with
* {@link WindowInsets#isVisible}.
*
- * @see #controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)
+ * @see #controlInputMethodAnimation
* @see #hideInputMethod()
*/
default void showInputMethod() {
@@ -196,7 +215,7 @@ public interface WindowInsetsController {
* the event by observing {@link View#onApplyWindowInsets} and checking visibility with
* {@link WindowInsets#isVisible}.
*
- * @see #controlInputMethodAnimation(long, WindowInsetsAnimationControlListener)
+ * @see #controlInputMethodAnimation
* @see #showInputMethod()
*/
default void hideInputMethod() {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cd9dee4f7329..55c298e2a92b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -421,7 +421,9 @@ public interface WindowManager extends ViewManager {
* </p>
*
* @return The display that this window manager is managing.
+ * @deprecated Use {@link Context#getDisplay()} instead.
*/
+ @Deprecated
public Display getDefaultDisplay();
/**
@@ -435,6 +437,49 @@ public interface WindowManager extends ViewManager {
public void removeViewImmediate(View view);
/**
+ * Returns the {@link WindowMetrics} according to the current system state.
+ * <p>
+ * The metrics describe the size of the area the window would occupy with
+ * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
+ * such a window would have.
+ * <p>
+ * The value of this is based on the <b>current</b> windowing state of the system.
+ *
+ * For example, for activities in multi-window mode, the metrics returned are based on the
+ * current bounds that the user has selected for the {@link android.app.Activity Activity}'s
+ * task.
+ *
+ * @see #getMaximumWindowMetrics()
+ * @see WindowMetrics
+ */
+ default @NonNull WindowMetrics getCurrentWindowMetrics() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the largets {@link WindowMetrics} an app may expect in the current system state.
+ * <p>
+ * The metrics describe the size of the largest potential area the window might occupy with
+ * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
+ * such a window would have.
+ * <p>
+ * The value of this is based on the largest <b>potential</b> windowing state of the system.
+ *
+ * For example, for activities in multi-window mode, the metrics returned are based on the
+ * what the bounds would be if the user expanded the {@link android.app.Activity Activity}'s
+ * task to cover the entire screen.
+ *
+ * Note that this might still be smaller than the size of the physical display if certain areas
+ * of the display are not available to windows created in this {@link Context}.
+ *
+ * @see #getMaximumWindowMetrics()
+ * @see WindowMetrics
+ */
+ default @NonNull WindowMetrics getMaximumWindowMetrics() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Used to asynchronously request Keyboard Shortcuts from the focused window.
*
* @hide
@@ -452,13 +497,48 @@ public interface WindowManager extends ViewManager {
* Message for taking fullscreen screenshot
* @hide
*/
- final int TAKE_SCREENSHOT_FULLSCREEN = 1;
+ int TAKE_SCREENSHOT_FULLSCREEN = 1;
/**
* Message for taking screenshot of selected region.
* @hide
*/
- final int TAKE_SCREENSHOT_SELECTED_REGION = 2;
+ int TAKE_SCREENSHOT_SELECTED_REGION = 2;
+
+ /**
+ * Message for handling a screenshot flow with an image provided by the caller.
+ * @hide
+ */
+ int TAKE_SCREENSHOT_PROVIDED_IMAGE = 3;
+
+ /**
+ * Parcel key for the screen shot bitmap sent with messages of type
+ * {@link #TAKE_SCREENSHOT_PROVIDED_IMAGE}, type {@link android.graphics.Bitmap}
+ * @hide
+ */
+ String PARCEL_KEY_SCREENSHOT_BITMAP = "screenshot_screen_bitmap";
+
+ /**
+ * Parcel key for the screen bounds of the image sent with messages of type
+ * [@link {@link #TAKE_SCREENSHOT_PROVIDED_IMAGE}], type {@link Rect} in screen coordinates.
+ * @hide
+ */
+ String PARCEL_KEY_SCREENSHOT_BOUNDS = "screenshot_screen_bounds";
+
+ /**
+ * Parcel key for the task id of the task that the screen shot was taken of, sent with messages
+ * of type [@link {@link #TAKE_SCREENSHOT_PROVIDED_IMAGE}], type int.
+ * @hide
+ */
+ String PARCEL_KEY_SCREENSHOT_TASK_ID = "screenshot_task_id";
+
+ /**
+ * Parcel key for the visible insets of the image sent with messages of type
+ * [@link {@link #TAKE_SCREENSHOT_PROVIDED_IMAGE}], type {@link android.graphics.Insets} in
+ * screen coordinates.
+ * @hide
+ */
+ String PARCEL_KEY_SCREENSHOT_INSETS = "screenshot_insets";
/**
* @hide
@@ -1243,11 +1323,9 @@ public interface WindowManager extends ViewManager {
* the device's screen turned on and bright. */
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
- /** Window flag: place the window within the entire screen, ignoring
- * decorations around the border (such as the status bar). The
- * window must correctly position its contents to take the screen
- * decoration into account. This flag is normally set for you
- * by Window as described in {@link Window#setFlags}.
+ /**
+ * Window flag for attached windows: Place the window within the entire screen, ignoring
+ * any constraints from the parent window.
*
* <p>Note: on displays that have a {@link DisplayCutout}, the window may be placed
* such that it avoids the {@link DisplayCutout} area if necessary according to the
@@ -1277,11 +1355,21 @@ public interface WindowManager extends ViewManager {
* {@link android.R.style#Theme_Holo_Light_NoActionBar_Fullscreen},
* {@link android.R.style#Theme_DeviceDefault_NoActionBar_Fullscreen}, and
* {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_Fullscreen}.</p>
+ *
+ * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()}
+ * instead.
*/
+ @Deprecated
public static final int FLAG_FULLSCREEN = 0x00000400;
- /** Window flag: override {@link #FLAG_FULLSCREEN} and force the
- * screen decorations (such as the status bar) to be shown. */
+ /**
+ * Window flag: override {@link #FLAG_FULLSCREEN} and force the
+ * screen decorations (such as the status bar) to be shown.
+ *
+ * @deprecated This value became API "by accident", and shouldn't be used by 3rd party
+ * applications.
+ */
+ @Deprecated
public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
/** Window flag: turn on dithering when compositing this window to
@@ -1313,13 +1401,18 @@ public interface WindowManager extends ViewManager {
* until the finger is released. */
public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;
- /** Window flag: a special option only for use in combination with
+ /**
+ * Window flag: a special option only for use in combination with
* {@link #FLAG_LAYOUT_IN_SCREEN}. When requesting layout in the
* screen your window may appear on top of or behind screen decorations
* such as the status bar. By also including this flag, the window
* manager will report the inset rectangle needed to ensure your
* content is not covered by screen decorations. This flag is normally
- * set for you by Window as described in {@link Window#setFlags}.*/
+ * set for you by Window as described in {@link Window#setFlags}
+ *
+ * @deprecated Insets will always be delivered to your application.
+ */
+ @Deprecated
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
/** Window flag: When set, input method can't interact with the focusable window
@@ -1505,7 +1598,11 @@ public interface WindowManager extends ViewManager {
*
* <p>Note: For devices that support
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE} this flag may be ignored.
+ *
+ * @deprecated Use {@link Window#setStatusBarColor(int)} with a half-translucent color
+ * instead.
*/
+ @Deprecated
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
/**
@@ -1528,7 +1625,11 @@ public interface WindowManager extends ViewManager {
* <p>Note: For devices that support
* {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE} this flag can be disabled
* by the car manufacturers.
+ *
+ * @deprecated Use {@link Window#setNavigationBarColor(int)} with a half-translucent color
+ * instead.
*/
+ @Deprecated
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
/**
@@ -1558,7 +1659,11 @@ public interface WindowManager extends ViewManager {
* overlap with the screen decorations of the parent window such as the navigation bar. By
* including this flag, the window manager will layout the attached window within the decor
* frame of the parent window such that it doesn't overlap with screen decorations.
+ *
+ * @deprecated Use {@link #setFitInsetsTypes(int)} to determine whether the attached
+ * window will overlap with system bars.
*/
+ @Deprecated
public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
/**
@@ -1878,13 +1983,6 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 0x10000000;
/**
- * Flag to indicate that the window only draws the bottom bar background so that we don't
- * extend it to system bar areas at other sides.
- * @hide
- */
- public static final int PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND = 0x20000000;
-
- /**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*
* @hide
@@ -1994,11 +2092,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
equals = PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
- name = "FIT_INSETS_CONTROLLED"),
- @ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND,
- equals = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND,
- name = "ONLY_DRAW_BOTTOM_BAR_BACKGROUND")
+ name = "FIT_INSETS_CONTROLLED")
})
@TestApi
public int privateFlags;
@@ -2098,7 +2192,11 @@ public interface WindowManager extends ViewManager {
* layout parameter flags include {@link #FLAG_FULLSCREEN}, this
* value for {@link #softInputMode} will be ignored; the window will
* not resize, but will stay fullscreen.
+ *
+ * @deprecated Use {@link Window#setOnContentApplyWindowInsetsListener} instead with a
+ * listener that fits {@link Type#ime()} instead.
*/
+ @Deprecated
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
/** Adjustment option for {@link #softInputMode}: set to have a window
@@ -2393,7 +2491,11 @@ public interface WindowManager extends ViewManager {
*
* @see View#STATUS_BAR_VISIBLE
* @see View#STATUS_BAR_HIDDEN
+ *
+ * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
+ * instead.
*/
+ @Deprecated
public int systemUiVisibility;
/**
@@ -2719,7 +2821,7 @@ public interface WindowManager extends ViewManager {
equals = WINDOW_DECOR,
name = "WINDOW_DECOR")
})
- private @InsetsType int mFitWindowInsetsTypes = Type.systemBars();
+ private @InsetsType int mFitInsetsTypes = Type.systemBars();
@ViewDebug.ExportedProperty(flagMapping = {
@ViewDebug.FlagToString(
@@ -2739,19 +2841,18 @@ public interface WindowManager extends ViewManager {
equals = BOTTOM,
name = "BOTTOM")
})
- private @InsetsSide int mFitWindowInsetsSides = Side.all();
+ private @InsetsSide int mFitInsetsSides = Side.all();
- private boolean mFitIgnoreVisibility = false;
+ private boolean mFitInsetsIgnoringVisibility = false;
/**
* Specifies types of insets that this window should avoid overlapping during layout.
*
* @param types which types of insets that this window should avoid. The initial value of
* this object includes all system bars.
- * @hide pending unhide
*/
- public void setFitWindowInsetsTypes(@InsetsType int types) {
- mFitWindowInsetsTypes = types;
+ public void setFitInsetsTypes(@InsetsType int types) {
+ mFitInsetsTypes = types;
privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
}
@@ -2760,10 +2861,9 @@ public interface WindowManager extends ViewManager {
*
* @param sides which sides that this window should avoid overlapping with the types
* specified. The initial value of this object includes all sides.
- * @hide pending unhide
*/
- public void setFitWindowInsetsSides(@InsetsSide int sides) {
- mFitWindowInsetsSides = sides;
+ public void setFitInsetsSides(@InsetsSide int sides) {
+ mFitInsetsSides = sides;
privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
}
@@ -2771,36 +2871,32 @@ public interface WindowManager extends ViewManager {
* Specifies if this window should fit the window insets no matter they are visible or not.
*
* @param ignore if true, this window will fit the given types even if they are not visible.
- * @hide pending unhide
*/
- public void setFitIgnoreVisibility(boolean ignore) {
- mFitIgnoreVisibility = ignore;
+ public void setFitInsetsIgnoringVisibility(boolean ignore) {
+ mFitInsetsIgnoringVisibility = ignore;
privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
}
/**
* @return the insets types that this window is avoiding overlapping.
- * @hide pending unhide
*/
- public @InsetsType int getFitWindowInsetsTypes() {
- return mFitWindowInsetsTypes;
+ public @InsetsType int getFitInsetsTypes() {
+ return mFitInsetsTypes;
}
/**
* @return the sides that this window is avoiding overlapping.
- * @hide pending unhide
*/
- public @InsetsSide int getFitWindowInsetsSides() {
- return mFitWindowInsetsSides;
+ public @InsetsSide int getFitInsetsSides() {
+ return mFitInsetsSides;
}
/**
* @return {@code true} if this window fits the window insets no matter they are visible or
* not.
- * @hide pending unhide
*/
- public boolean getFitIgnoreVisibility() {
- return mFitIgnoreVisibility;
+ public boolean isFitInsetsIgnoringVisibility() {
+ return mFitInsetsIgnoringVisibility;
}
public LayoutParams() {
@@ -2966,9 +3062,9 @@ public interface WindowManager extends ViewManager {
out.writeLong(hideTimeoutMilliseconds);
out.writeInt(insetsFlags.appearance);
out.writeInt(insetsFlags.behavior);
- out.writeInt(mFitWindowInsetsTypes);
- out.writeInt(mFitWindowInsetsSides);
- out.writeBoolean(mFitIgnoreVisibility);
+ out.writeInt(mFitInsetsTypes);
+ out.writeInt(mFitInsetsSides);
+ out.writeBoolean(mFitInsetsIgnoringVisibility);
out.writeBoolean(preferMinimalPostProcessing);
}
@@ -3027,9 +3123,9 @@ public interface WindowManager extends ViewManager {
hideTimeoutMilliseconds = in.readLong();
insetsFlags.appearance = in.readInt();
insetsFlags.behavior = in.readInt();
- mFitWindowInsetsTypes = in.readInt();
- mFitWindowInsetsSides = in.readInt();
- mFitIgnoreVisibility = in.readBoolean();
+ mFitInsetsTypes = in.readInt();
+ mFitInsetsSides = in.readInt();
+ mFitInsetsIgnoringVisibility = in.readBoolean();
preferMinimalPostProcessing = in.readBoolean();
}
@@ -3276,18 +3372,18 @@ public interface WindowManager extends ViewManager {
changes |= INSET_FLAGS_CHANGED;
}
- if (mFitWindowInsetsTypes != o.mFitWindowInsetsTypes) {
- mFitWindowInsetsTypes = o.mFitWindowInsetsTypes;
+ if (mFitInsetsTypes != o.mFitInsetsTypes) {
+ mFitInsetsTypes = o.mFitInsetsTypes;
changes |= LAYOUT_CHANGED;
}
- if (mFitWindowInsetsSides != o.mFitWindowInsetsSides) {
- mFitWindowInsetsSides = o.mFitWindowInsetsSides;
+ if (mFitInsetsSides != o.mFitInsetsSides) {
+ mFitInsetsSides = o.mFitInsetsSides;
changes |= LAYOUT_CHANGED;
}
- if (mFitIgnoreVisibility != o.mFitIgnoreVisibility) {
- mFitIgnoreVisibility = o.mFitIgnoreVisibility;
+ if (mFitInsetsIgnoringVisibility != o.mFitInsetsIgnoringVisibility) {
+ mFitInsetsIgnoringVisibility = o.mFitInsetsIgnoringVisibility;
changes |= LAYOUT_CHANGED;
}
@@ -3449,17 +3545,17 @@ public interface WindowManager extends ViewManager {
sb.append(prefix).append(" bhv=").append(ViewDebug.flagsToString(
InsetsFlags.class, "behavior", insetsFlags.behavior));
}
- if (mFitWindowInsetsTypes != 0) {
+ if (mFitInsetsTypes != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" fitTypes=").append(ViewDebug.flagsToString(
- LayoutParams.class, "mFitWindowInsetsTypes", mFitWindowInsetsTypes));
+ LayoutParams.class, "mFitInsetsTypes", mFitInsetsTypes));
}
- if (mFitWindowInsetsSides != Side.all()) {
+ if (mFitInsetsSides != Side.all()) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" fitSides=").append(ViewDebug.flagsToString(
- LayoutParams.class, "mFitWindowInsetsSides", mFitWindowInsetsSides));
+ LayoutParams.class, "mFitInsetsSides", mFitInsetsSides));
}
- if (mFitIgnoreVisibility) {
+ if (mFitInsetsIgnoringVisibility) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" fitIgnoreVis");
}
@@ -3500,9 +3596,9 @@ public interface WindowManager extends ViewManager {
proto.write(SUBTREE_SYSTEM_UI_VISIBILITY_FLAGS, subtreeSystemUiVisibility);
proto.write(APPEARANCE, insetsFlags.appearance);
proto.write(BEHAVIOR, insetsFlags.behavior);
- proto.write(FIT_INSETS_TYPES, mFitWindowInsetsTypes);
- proto.write(FIT_INSETS_SIDES, mFitWindowInsetsSides);
- proto.write(FIT_IGNORE_VISIBILITY, mFitIgnoreVisibility);
+ proto.write(FIT_INSETS_TYPES, mFitInsetsTypes);
+ proto.write(FIT_INSETS_SIDES, mFitInsetsSides);
+ proto.write(FIT_IGNORE_VISIBILITY, mFitInsetsIgnoringVisibility);
proto.end(token);
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index cdeeaa438acb..4365d1f5194a 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -17,12 +17,17 @@
package android.view;
import android.annotation.NonNull;
+import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Size;
import com.android.internal.os.IResultReceiver;
@@ -62,6 +67,10 @@ public final class WindowManagerImpl implements WindowManager {
private IBinder mDefaultToken;
+ private boolean mIsViewAdded;
+ private View mLastView;
+ private WindowManager.LayoutParams mLastParams;
+
public WindowManagerImpl(Context context) {
this(context, null);
}
@@ -93,6 +102,9 @@ public final class WindowManagerImpl implements WindowManager {
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
+ mIsViewAdded = true;
+ mLastView = view;
+ mLastParams = (WindowManager.LayoutParams) params;
}
@Override
@@ -201,4 +213,71 @@ public final class WindowManagerImpl implements WindowManager {
}
return false;
}
+
+ @Override
+ public WindowMetrics getCurrentWindowMetrics() {
+ final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
+ final Rect bound = getCurrentBounds(context);
+
+ return new WindowMetrics(toSize(bound), computeWindowInsets());
+ }
+
+ private static Rect getCurrentBounds(Context context) {
+ synchronized (ResourcesManager.getInstance()) {
+ return context.getResources().getConfiguration().windowConfiguration.getBounds();
+ }
+ }
+
+ @Override
+ public WindowMetrics getMaximumWindowMetrics() {
+ return new WindowMetrics(toSize(getMaximumBounds()), computeWindowInsets());
+ }
+
+ private Size toSize(Rect frame) {
+ return new Size(frame.width(), frame.height());
+ }
+
+ private Rect getMaximumBounds() {
+ // TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
+ // bound after displayArea feature is finished.
+ final Display display = mContext.getDisplay();
+ final Point displaySize = new Point();
+ display.getRealSize(displaySize);
+ return new Rect(0, 0, displaySize.x, displaySize.y);
+ }
+
+ private WindowInsets computeWindowInsets() {
+ // TODO(window-context): This can only be properly implemented
+ // once we flip the new insets mode flag.
+ if (mParentWindow != null) {
+ if (mParentWindow.getDecorView().isAttachedToWindow()) {
+ return mParentWindow.getDecorView().getViewRootImpl()
+ .getWindowInsets(true /* forceConstruct */);
+ }
+ return getWindowInsetsFromServer(mParentWindow.getAttributes());
+ }
+ if (mIsViewAdded) {
+ return mLastView.getViewRootImpl().getWindowInsets(true /* forceConstruct */);
+ } else {
+ return getWindowInsetsFromServer(new WindowManager.LayoutParams());
+ }
+
+ }
+
+ private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) {
+ try {
+ final Rect systemWindowInsets = new Rect();
+ final Rect stableInsets = new Rect();
+ final DisplayCutout.ParcelableWrapper displayCutout =
+ new DisplayCutout.ParcelableWrapper();
+ WindowManagerGlobal.getWindowManagerService().getWindowInsets(attrs,
+ mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout);
+ return new WindowInsets.Builder()
+ .setSystemWindowInsets(Insets.of(systemWindowInsets))
+ .setStableInsets(Insets.of(stableInsets))
+ .setDisplayCutout(displayCutout.get()).build();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
}
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
new file mode 100644
index 000000000000..8caf5b7fc725
--- /dev/null
+++ b/core/java/android/view/WindowMetrics.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.util.Size;
+
+/**
+ * Metrics about a Window, consisting of the size and {@link WindowInsets}.
+ * <p>
+ * This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
+ * {@link WindowManager#getMaximumWindowMetrics()}.
+ *
+ * @see WindowInsets#getInsets(int)
+ * @see WindowManager#getCurrentWindowMetrics()
+ * @see WindowManager#getMaximumWindowMetrics()
+ */
+public final class WindowMetrics {
+ private final @NonNull Size mSize;
+ private final @NonNull WindowInsets mWindowInsets;
+
+ public WindowMetrics(@NonNull Size size, @NonNull WindowInsets windowInsets) {
+ mSize = size;
+ mWindowInsets = windowInsets;
+ }
+
+ /**
+ * Returns the size of the window.
+ *
+ * @return window size in pixel.
+ */
+ public @NonNull Size getSize() {
+ return mSize;
+ }
+
+ /**
+ * Returns the {@link WindowInsets} of the window.
+ *
+ * @return the {@link WindowInsets} of the window.
+ */
+ public @NonNull WindowInsets getWindowInsets() {
+ return mWindowInsets;
+ }
+}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index a26243c7cad5..c80a1ae55228 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -18,6 +18,8 @@ package android.view.inputmethod;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.os.Bundle;
@@ -28,7 +30,13 @@ import android.os.UserHandle;
import android.text.InputType;
import android.text.TextUtils;
import android.util.Printer;
+import android.view.View;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -491,6 +499,238 @@ public class EditorInfo implements InputType, Parcelable {
@Nullable
public UserHandle targetInputMethodUser = null;
+ @IntDef({TrimPolicy.HEAD, TrimPolicy.TAIL})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface TrimPolicy {
+ int HEAD = 0;
+ int TAIL = 1;
+ }
+
+ /**
+ * The maximum length of initialSurroundingText. When the input text from
+ * {@code setInitialSurroundingText(CharSequence)} is longer than this, trimming shall be
+ * performed to keep memory efficiency.
+ */
+ @VisibleForTesting
+ static final int MEMORY_EFFICIENT_TEXT_LENGTH = 2048;
+ /**
+ * When the input text is longer than {@code #MEMORY_EFFICIENT_TEXT_LENGTH}, we start trimming
+ * the input text into three parts: BeforeCursor, Selection, and AfterCursor. We don't want to
+ * trim the Selection but we also don't want it consumes all available space. Therefore, the
+ * maximum acceptable Selection length is half of {@code #MEMORY_EFFICIENT_TEXT_LENGTH}.
+ */
+ @VisibleForTesting
+ static final int MAX_INITIAL_SELECTION_LENGTH = MEMORY_EFFICIENT_TEXT_LENGTH / 2;
+
+ @NonNull
+ private InitialSurroundingText mInitialSurroundingText = new InitialSurroundingText();
+
+ /**
+ * Editors may use this method to provide initial input text to IMEs. As the surrounding text
+ * could be used to provide various input assistance, we recommend editors to provide the
+ * complete initial input text in its {@link View#onCreateInputConnection(EditorInfo)} callback.
+ * The supplied text will then be processed to serve {@code #getInitialTextBeforeCursor},
+ * {@code #getInitialSelectedText}, and {@code #getInitialTextBeforeCursor}. System is allowed
+ * to trim {@code sourceText} for various reasons while keeping the most valuable data to IMEs.
+ *
+ * <p><strong>Editor authors: </strong>Providing the initial input text helps reducing IPC calls
+ * for IMEs to provide many modern features right after the connection setup. We recommend
+ * calling this method in your implementation.
+ *
+ * @param sourceText The complete input text.
+ */
+ public void setInitialSurroundingText(@NonNull CharSequence sourceText) {
+ setInitialSurroundingSubText(sourceText, /* subTextStart = */ 0);
+ }
+
+ /**
+ * Editors may use this method to provide initial input text to IMEs. As the surrounding text
+ * could be used to provide various input assistance, we recommend editors to provide the
+ * complete initial input text in its {@link View#onCreateInputConnection(EditorInfo)} callback.
+ * When trimming the input text is needed, call this method instead of
+ * {@code setInitialSurroundingText(CharSequence)} and provide the trimmed position info. Always
+ * try to include the selected text within {@code subText} to give the system best flexibility
+ * to choose where and how to trim {@code subText} when necessary.
+ *
+ * @param subText The input text. When it was trimmed, {@code subTextStart} must be provided
+ * correctly.
+ * @param subTextStart The position that the input text got trimmed. For example, when the
+ * editor wants to trim out the first 10 chars, subTextStart should be 10.
+ */
+ public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) {
+ Preconditions.checkNotNull(subText);
+
+ // Swap selection start and end if necessary.
+ final int subTextSelStart = initialSelStart > initialSelEnd
+ ? initialSelEnd - subTextStart : initialSelStart - subTextStart;
+ final int subTextSelEnd = initialSelStart > initialSelEnd
+ ? initialSelStart - subTextStart : initialSelEnd - subTextStart;
+
+ final int subTextLength = subText.length();
+ // Unknown or invalid selection.
+ if (subTextStart < 0 || subTextSelStart < 0 || subTextSelEnd > subTextLength) {
+ mInitialSurroundingText = new InitialSurroundingText();
+ return;
+ }
+
+ // For privacy protection reason, we don't carry password inputs to IMEs.
+ if (isPasswordInputType(inputType)) {
+ mInitialSurroundingText = new InitialSurroundingText();
+ return;
+ }
+
+ if (subTextLength <= MEMORY_EFFICIENT_TEXT_LENGTH) {
+ mInitialSurroundingText = new InitialSurroundingText(subText, subTextSelStart,
+ subTextSelEnd);
+ return;
+ }
+
+ // The input text is too long. Let's try to trim it reasonably. Fundamental rules are:
+ // 1. Text before the cursor is the most important information to IMEs.
+ // 2. Text after the cursor is the second important information to IMEs.
+ // 3. Selected text is the least important information but it shall NEVER be truncated.
+ // When it is too long, just drop it.
+ //
+ // Source: <TextBeforeCursor><Selection><TextAfterCursor>
+ // Possible results:
+ // 1. <(maybeTrimmedAtHead)TextBeforeCursor><Selection><TextAfterCursor(maybeTrimmedAtTail)>
+ // 2. <(maybeTrimmedAtHead)TextBeforeCursor><TextAfterCursor(maybeTrimmedAtTail)>
+ //
+ final int sourceSelLength = subTextSelEnd - subTextSelStart;
+ // When the selected text is too long, drop it.
+ final int newSelLength = (sourceSelLength > MAX_INITIAL_SELECTION_LENGTH)
+ ? 0 : sourceSelLength;
+
+ // Distribute rest of length quota to TextBeforeCursor and TextAfterCursor in 4:1 ratio.
+ final int subTextBeforeCursorLength = subTextSelStart;
+ final int subTextAfterCursorLength = subTextLength - subTextSelEnd;
+ final int maxLengthMinusSelection = MEMORY_EFFICIENT_TEXT_LENGTH - newSelLength;
+ final int possibleMaxBeforeCursorLength =
+ Math.min(subTextBeforeCursorLength, (int) (0.8 * maxLengthMinusSelection));
+ int newAfterCursorLength = Math.min(subTextAfterCursorLength,
+ maxLengthMinusSelection - possibleMaxBeforeCursorLength);
+ int newBeforeCursorLength = Math.min(subTextBeforeCursorLength,
+ maxLengthMinusSelection - newAfterCursorLength);
+
+ // As trimming may happen at the head of TextBeforeCursor, calculate new starting position.
+ int newBeforeCursorHead = subTextBeforeCursorLength - newBeforeCursorLength;
+
+ // We don't want to cut surrogate pairs in the middle. Exam that at the new head and tail.
+ if (isCutOnSurrogate(subText,
+ subTextSelStart - newBeforeCursorLength, TrimPolicy.HEAD)) {
+ newBeforeCursorHead = newBeforeCursorHead + 1;
+ newBeforeCursorLength = newBeforeCursorLength - 1;
+ }
+ if (isCutOnSurrogate(subText,
+ subTextSelEnd + newAfterCursorLength - 1, TrimPolicy.TAIL)) {
+ newAfterCursorLength = newAfterCursorLength - 1;
+ }
+
+ // Now we know where to trim, compose the initialSurroundingText.
+ final int newTextLength = newBeforeCursorLength + newSelLength + newAfterCursorLength;
+ CharSequence newInitialSurroundingText;
+ if (newSelLength != sourceSelLength) {
+ final CharSequence beforeCursor = subText.subSequence(newBeforeCursorHead,
+ newBeforeCursorHead + newBeforeCursorLength);
+
+ final CharSequence afterCursor = subText.subSequence(subTextSelEnd,
+ subTextSelEnd + newAfterCursorLength);
+
+ newInitialSurroundingText = TextUtils.concat(beforeCursor, afterCursor);
+ } else {
+ newInitialSurroundingText = subText
+ .subSequence(newBeforeCursorHead, newBeforeCursorHead + newTextLength);
+ }
+
+ // As trimming may happen at the head, adjust cursor position in the initialSurroundingText
+ // obj.
+ newBeforeCursorHead = 0;
+ final int newSelHead = newBeforeCursorHead + newBeforeCursorLength;
+ mInitialSurroundingText = new InitialSurroundingText(
+ newInitialSurroundingText, newSelHead, newSelHead + newSelLength);
+ }
+
+ /**
+ * Get <var>n</var> characters of text before the current cursor position. May be {@code null}
+ * when the protocol is not supported.
+ *
+ * @param length The expected length of the text.
+ * @param flags Supplies additional options controlling how the text is returned. May be
+ * either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+ * @return the text before the cursor position; the length of the returned text might be less
+ * than <var>n</var>. When there is no text before the cursor, an empty string will be returned.
+ * It could also be {@code null} when the editor or system could not support this protocol.
+ */
+ @Nullable
+ public CharSequence getInitialTextBeforeCursor(int length, int flags) {
+ return mInitialSurroundingText.getInitialTextBeforeCursor(length, flags);
+ }
+
+ /**
+ * Gets the selected text, if any. May be {@code null} when no text is selected or the selected
+ * text is way too long.
+ *
+ * @param flags Supplies additional options controlling how the text is returned. May be
+ * either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+ * @return the text that is currently selected, if any. It could be an empty string when there
+ * is no text selected. When {@code null} is returned, the selected text might be too long or
+ * this protocol is not supported.
+ */
+ @Nullable
+ public CharSequence getInitialSelectedText(int flags) {
+ // Swap selection start and end if necessary.
+ final int correctedTextSelStart = initialSelStart > initialSelEnd
+ ? initialSelEnd : initialSelStart;
+ final int correctedTextSelEnd = initialSelStart > initialSelEnd
+ ? initialSelStart : initialSelEnd;
+
+ final int sourceSelLength = correctedTextSelEnd - correctedTextSelStart;
+ if (initialSelStart < 0 || initialSelEnd < 0
+ || mInitialSurroundingText.getSelectionLength() != sourceSelLength) {
+ return null;
+ }
+ return mInitialSurroundingText.getInitialSelectedText(flags);
+ }
+
+ /**
+ * Get <var>n</var> characters of text after the current cursor position. May be {@code null}
+ * when the protocol is not supported.
+ *
+ * @param length The expected length of the text.
+ * @param flags Supplies additional options controlling how the text is returned. May be
+ * either 0 or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+ * @return the text after the cursor position; the length of the returned text might be less
+ * than <var>n</var>. When there is no text after the cursor, an empty string will be returned.
+ * It could also be {@code null} when the editor or system could not support this protocol.
+ */
+ @Nullable
+ public CharSequence getInitialTextAfterCursor(int length, int flags) {
+ return mInitialSurroundingText.getInitialTextAfterCursor(length, flags);
+ }
+
+ private static boolean isCutOnSurrogate(CharSequence sourceText, int cutPosition,
+ @TrimPolicy int policy) {
+ switch (policy) {
+ case TrimPolicy.HEAD:
+ return Character.isLowSurrogate(sourceText.charAt(cutPosition));
+ case TrimPolicy.TAIL:
+ return Character.isHighSurrogate(sourceText.charAt(cutPosition));
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isPasswordInputType(int inputType) {
+ final int variation =
+ inputType & (TYPE_MASK_CLASS | TYPE_MASK_VARIATION);
+ return variation
+ == (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD)
+ || variation
+ == (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_WEB_PASSWORD)
+ || variation
+ == (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD);
+ }
+
/**
* Ensure that the data in this EditorInfo is compatible with an application
* that was developed against the given target API version. This can
@@ -573,6 +813,7 @@ public class EditorInfo implements InputType, Parcelable {
dest.writeInt(fieldId);
dest.writeString(fieldName);
dest.writeBundle(extras);
+ mInitialSurroundingText.writeToParcel(dest, flags);
if (hintLocales != null) {
hintLocales.writeToParcel(dest, flags);
} else {
@@ -603,6 +844,9 @@ public class EditorInfo implements InputType, Parcelable {
res.fieldId = source.readInt();
res.fieldName = source.readString();
res.extras = source.readBundle();
+ InitialSurroundingText initialSurroundingText =
+ InitialSurroundingText.CREATOR.createFromParcel(source);
+ res.mInitialSurroundingText = initialSurroundingText;
LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
res.contentMimeTypes = source.readStringArray();
@@ -619,4 +863,93 @@ public class EditorInfo implements InputType, Parcelable {
return 0;
}
+ // TODO(b/148035211): Unit tests for this class
+ static final class InitialSurroundingText implements Parcelable {
+ @Nullable final CharSequence mSurroundingText;
+ final int mSelectionHead;
+ final int mSelectionEnd;
+
+ InitialSurroundingText() {
+ mSurroundingText = null;
+ mSelectionHead = 0;
+ mSelectionEnd = 0;
+ }
+
+ InitialSurroundingText(@Nullable CharSequence surroundingText, int selectionHead,
+ int selectionEnd) {
+ mSurroundingText = surroundingText;
+ mSelectionHead = selectionHead;
+ mSelectionEnd = selectionEnd;
+ }
+
+ @Nullable
+ private CharSequence getInitialTextBeforeCursor(int n, int flags) {
+ if (mSurroundingText == null) {
+ return null;
+ }
+
+ final int length = Math.min(n, mSelectionHead);
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mSurroundingText.subSequence(mSelectionHead - length, mSelectionHead)
+ : TextUtils.substring(mSurroundingText, mSelectionHead - length,
+ mSelectionHead);
+ }
+
+ @Nullable
+ private CharSequence getInitialSelectedText(int flags) {
+ if (mSurroundingText == null) {
+ return null;
+ }
+
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mSurroundingText.subSequence(mSelectionHead, mSelectionEnd)
+ : TextUtils.substring(mSurroundingText, mSelectionHead, mSelectionEnd);
+ }
+
+ @Nullable
+ private CharSequence getInitialTextAfterCursor(int n, int flags) {
+ if (mSurroundingText == null) {
+ return null;
+ }
+
+ final int length = Math.min(n, mSurroundingText.length() - mSelectionEnd);
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mSurroundingText.subSequence(mSelectionEnd, mSelectionEnd + length)
+ : TextUtils.substring(mSurroundingText, mSelectionEnd, mSelectionEnd + length);
+ }
+
+ private int getSelectionLength() {
+ return mSelectionEnd - mSelectionHead;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ TextUtils.writeToParcel(mSurroundingText, dest, flags);
+ dest.writeInt(mSelectionHead);
+ dest.writeInt(mSelectionEnd);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<InitialSurroundingText>
+ CREATOR = new Parcelable.Creator<InitialSurroundingText>() {
+ @Override
+ public InitialSurroundingText createFromParcel(Parcel source) {
+ final CharSequence initialText =
+ TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ final int selectionHead = source.readInt();
+ final int selectionEnd = source.readInt();
+
+ return new InitialSurroundingText(initialText, selectionHead, selectionEnd);
+ }
+
+ @Override
+ public InitialSurroundingText[] newArray(int size) {
+ return new InitialSurroundingText[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 195b63a8fc8e..703b64f8224f 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -18,6 +18,7 @@ package android.view.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.os.Parcelable;
import android.view.inline.InlinePresentationSpec;
@@ -45,6 +46,17 @@ public final class InlineSuggestionInfo implements Parcelable {
*/
public static final @Source String SOURCE_PLATFORM = "android:platform";
+ /**
+ * UI type: the UI contains an Autofill suggestion that will autofill the fields when tapped.
+ */
+ public static final @Type String TYPE_SUGGESTION = "android:autofill:suggestion";
+
+ /**
+ * UI type: the UI contains an widget that will launch an intent when tapped.
+ */
+ @SuppressLint({"IntentName"})
+ public static final @Type String TYPE_ACTION = "android:autofill:action";
+
/** The presentation spec to which the inflated suggestion view abides. */
private final @NonNull InlinePresentationSpec mPresentationSpec;
@@ -54,6 +66,9 @@ public final class InlineSuggestionInfo implements Parcelable {
/** Hints for the type of data being suggested. */
private final @Nullable String[] mAutofillHints;
+ /** The type of the UI. */
+ private final @NonNull @Type String mType;
+
/**
* Creates a new {@link InlineSuggestionInfo}, for testing purpose.
*
@@ -65,7 +80,8 @@ public final class InlineSuggestionInfo implements Parcelable {
@NonNull InlinePresentationSpec presentationSpec,
@NonNull @Source String source,
@Nullable String[] autofillHints) {
- return new InlineSuggestionInfo(presentationSpec, source, autofillHints);
+ // TODO(b/147394280): Add CTS test for the type field.
+ return new InlineSuggestionInfo(presentationSpec, source, autofillHints, TYPE_SUGGESTION);
}
@@ -92,6 +108,15 @@ public final class InlineSuggestionInfo implements Parcelable {
@DataClass.Generated.Member
public @interface Source {}
+ /** @hide */
+ @android.annotation.StringDef(prefix = "TYPE_", value = {
+ TYPE_SUGGESTION,
+ TYPE_ACTION
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Type {}
+
/**
* Creates a new InlineSuggestionInfo.
*
@@ -101,13 +126,16 @@ public final class InlineSuggestionInfo implements Parcelable {
* The source from which the suggestion is provided.
* @param autofillHints
* Hints for the type of data being suggested.
+ * @param type
+ * The type of the UI.
* @hide
*/
@DataClass.Generated.Member
public InlineSuggestionInfo(
@NonNull InlinePresentationSpec presentationSpec,
@NonNull @Source String source,
- @Nullable String[] autofillHints) {
+ @Nullable String[] autofillHints,
+ @NonNull @Type String type) {
this.mPresentationSpec = presentationSpec;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPresentationSpec);
@@ -124,6 +152,18 @@ public final class InlineSuggestionInfo implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mSource);
this.mAutofillHints = autofillHints;
+ this.mType = type;
+
+ if (!(java.util.Objects.equals(mType, TYPE_SUGGESTION))
+ && !(java.util.Objects.equals(mType, TYPE_ACTION))) {
+ throw new java.lang.IllegalArgumentException(
+ "type was " + mType + " but must be one of: "
+ + "TYPE_SUGGESTION(" + TYPE_SUGGESTION + "), "
+ + "TYPE_ACTION(" + TYPE_ACTION + ")");
+ }
+
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mType);
// onConstructed(); // You can define this method to get a callback
}
@@ -152,6 +192,14 @@ public final class InlineSuggestionInfo implements Parcelable {
return mAutofillHints;
}
+ /**
+ * The type of the UI.
+ */
+ @DataClass.Generated.Member
+ public @NonNull @Type String getType() {
+ return mType;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -161,7 +209,8 @@ public final class InlineSuggestionInfo implements Parcelable {
return "InlineSuggestionInfo { " +
"presentationSpec = " + mPresentationSpec + ", " +
"source = " + mSource + ", " +
- "autofillHints = " + java.util.Arrays.toString(mAutofillHints) +
+ "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + ", " +
+ "type = " + mType +
" }";
}
@@ -180,7 +229,8 @@ public final class InlineSuggestionInfo implements Parcelable {
return true
&& java.util.Objects.equals(mPresentationSpec, that.mPresentationSpec)
&& java.util.Objects.equals(mSource, that.mSource)
- && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints);
+ && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints)
+ && java.util.Objects.equals(mType, that.mType);
}
@Override
@@ -193,6 +243,7 @@ public final class InlineSuggestionInfo implements Parcelable {
_hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpec);
_hash = 31 * _hash + java.util.Objects.hashCode(mSource);
_hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mType);
return _hash;
}
@@ -208,6 +259,7 @@ public final class InlineSuggestionInfo implements Parcelable {
dest.writeTypedObject(mPresentationSpec, flags);
dest.writeString(mSource);
if (mAutofillHints != null) dest.writeStringArray(mAutofillHints);
+ dest.writeString(mType);
}
@Override
@@ -225,6 +277,7 @@ public final class InlineSuggestionInfo implements Parcelable {
InlinePresentationSpec presentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR);
String source = in.readString();
String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray();
+ String type = in.readString();
this.mPresentationSpec = presentationSpec;
com.android.internal.util.AnnotationValidations.validate(
@@ -242,6 +295,18 @@ public final class InlineSuggestionInfo implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mSource);
this.mAutofillHints = autofillHints;
+ this.mType = type;
+
+ if (!(java.util.Objects.equals(mType, TYPE_SUGGESTION))
+ && !(java.util.Objects.equals(mType, TYPE_ACTION))) {
+ throw new java.lang.IllegalArgumentException(
+ "type was " + mType + " but must be one of: "
+ + "TYPE_SUGGESTION(" + TYPE_SUGGESTION + "), "
+ + "TYPE_ACTION(" + TYPE_ACTION + ")");
+ }
+
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mType);
// onConstructed(); // You can define this method to get a callback
}
@@ -261,10 +326,10 @@ public final class InlineSuggestionInfo implements Parcelable {
};
@DataClass.Generated(
- time = 1578972121865L,
+ time = 1579806757327L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java",
- inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+ inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index e5545405728d..4337ed5109db 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -158,7 +158,11 @@ public interface InputConnection {
* trigger an IPC round-trip that will take some time. Assume this
* method consumes a lot of time. Also, please keep in mind the
* Editor may choose to return less characters than requested even
- * if they are available for performance reasons.</p>
+ * if they are available for performance reasons. If you are using
+ * this to get the initial text around the cursor, you may consider
+ * using {@link EditorInfo#getInitialTextBeforeCursor(int, int)},
+ * {@link EditorInfo#getInitialSelectedText(int)}, and
+ * {@link EditorInfo#getInitialTextAfterCursor(int, int)} to prevent IPC costs.</p>
*
* <p><strong>Editor authors:</strong> please be careful of race
* conditions in implementing this call. An IME can make a change
@@ -196,7 +200,11 @@ public interface InputConnection {
*
* <p><strong>IME authors:</strong> please consider this will
* trigger an IPC round-trip that will take some time. Assume this
- * method consumes a lot of time.</p>
+ * method consumes a lot of time. If you are using this to get the
+ * initial text around the cursor, you may consider using
+ * {@link EditorInfo#getInitialTextBeforeCursor(int, int)},
+ * {@link EditorInfo#getInitialSelectedText(int)}, and
+ * {@link EditorInfo#getInitialTextAfterCursor(int, int)} to prevent IPC costs.</p>
*
* <p><strong>Editor authors:</strong> please be careful of race
* conditions in implementing this call. An IME can make a change
@@ -234,7 +242,11 @@ public interface InputConnection {
*
* <p><strong>IME authors:</strong> please consider this will
* trigger an IPC round-trip that will take some time. Assume this
- * method consumes a lot of time.</p>
+ * method consumes a lot of time. If you are using this to get the
+ * initial text around the cursor, you may consider using
+ * {@link EditorInfo#getInitialTextBeforeCursor(int, int)},
+ * {@link EditorInfo#getInitialSelectedText(int)}, and
+ * {@link EditorInfo#getInitialTextAfterCursor(int, int)} to prevent IPC costs.</p>
*
* <p><strong>Editor authors:</strong> please be careful of race
* conditions in implementing this call. An IME can make a change
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b10631b7ef2f..7fd41508dfc3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -391,6 +391,9 @@ public class Editor {
// This can only be true if the text view is editable.
private boolean mCursorControlEnabled;
+ // Specifies whether the new magnifier (with fish-eye effect) is enabled.
+ private final boolean mNewMagnifierEnabled;
+
Editor(TextView textView) {
mTextView = textView;
// Synchronize the filter list, which places the undo input filter at the end.
@@ -401,9 +404,13 @@ public class Editor {
mCursorControlEnabled = AppGlobals.getIntCoreSetting(
WidgetFlags.KEY_ENABLE_CURSOR_CONTROL , 0) != 0;
+ mNewMagnifierEnabled = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, 0) != 0;
if (TextView.DEBUG_CURSOR) {
logCursor("Editor", "Cursor control is %s.",
mCursorControlEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "New magnifier is %s.",
+ mNewMagnifierEnabled ? "enabled" : "disabled");
}
}
@@ -422,7 +429,7 @@ public class Editor {
if (FLAG_USE_MAGNIFIER && mMagnifierAnimator == null) {
// Lazy creates the magnifier instance because it requires the text height which cannot
// be measured at the time of Editor instance being created.
- final Magnifier.Builder builder = shouldUseNewMagnifier()
+ final Magnifier.Builder builder = mNewMagnifierEnabled
? createBuilderWithInlineMagnifierDefaults()
: Magnifier.createBuilderWithOldMagnifierDefaults(mTextView);
mMagnifierAnimator = new MagnifierMotionAnimator(builder.build());
@@ -430,24 +437,28 @@ public class Editor {
return mMagnifierAnimator;
}
- private boolean shouldUseNewMagnifier() {
- // TODO: use a separate flag to enable new magnifier.
- return mCursorControlEnabled;
- }
-
private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() {
final Magnifier.Builder params = new Magnifier.Builder(mTextView);
// TODO: supports changing the height/width dynamically because the text height can be
// dynamically changed.
+ float zoom = AppGlobals.getFloatCoreSetting(
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f);
+ float aspectRatio = AppGlobals.getFloatCoreSetting(
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, 5.5f);
+ // Avoid invalid/unsupported values.
+ if (zoom < 1.2f || zoom > 1.8f) {
+ zoom = 1.5f;
+ }
+ if (aspectRatio < 3 || aspectRatio > 8) {
+ aspectRatio = 5.5f;
+ }
+
final Paint.FontMetrics fontMetrics = mTextView.getPaint().getFontMetrics();
final float sourceHeight = fontMetrics.descent - fontMetrics.ascent;
- final float zoom = 1.5f;
- final float widthHeightRatio = 5.5f;
// Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
int height = (int)(sourceHeight * zoom) + 2;
- int width = (int)(widthHeightRatio * height);
-
+ int width = (int)(aspectRatio * height);
params.setFishEyeStyle()
.setSize(width, height)
@@ -4680,11 +4691,11 @@ public class Editor {
}
};
- private int getPreferredWidth() {
+ protected final int getPreferredWidth() {
return Math.max(mDrawable.getIntrinsicWidth(), mMinSize);
}
- private int getPreferredHeight() {
+ protected final int getPreferredHeight() {
return Math.max(mDrawable.getIntrinsicHeight(), mMinSize);
}
@@ -5089,14 +5100,14 @@ public class Editor {
mTextView.invalidateCursorPath();
suspendBlink();
- if (shouldUseNewMagnifier()) {
+ if (mNewMagnifierEnabled) {
// Calculates the line bounds as the content source bounds to the magnifier.
Layout layout = mTextView.getLayout();
int line = layout.getLineForOffset(getCurrentCursorOffset());
int lineLeft = (int) layout.getLineLeft(line);
lineLeft += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
int lineRight = (int) layout.getLineRight(line);
- lineRight -= mTextView.getTotalPaddingRight() + mTextView.getScrollX();
+ lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
}
mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
@@ -5218,7 +5229,7 @@ public class Editor {
// Whether the popup window is in the invisible state and will be dismissed when finger up.
private boolean mPendingDismissOnUp = false;
// The alpha value of the drawable.
- private final int mDrawableOpacity = 255;
+ private final int mDrawableOpacity;
// Members for toggling the insertion menu in touch through mode.
@@ -5239,8 +5250,29 @@ public class Editor {
// of the touch through events.
private float mTextHeight;
- public InsertionHandleView(Drawable drawable) {
+ // The delta height applied to the insertion handle view.
+ private final int mDeltaHeight;
+
+ InsertionHandleView(Drawable drawable) {
super(drawable, drawable, com.android.internal.R.id.insertion_handle);
+
+ int deltaHeight = 0;
+ int opacity = 255;
+ if (mCursorControlEnabled) {
+ deltaHeight = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, 25);
+ opacity = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, 50);
+ // Avoid invalid/unsupported values.
+ if (deltaHeight < -25 || deltaHeight > 50) {
+ deltaHeight = 25;
+ }
+ if (opacity < 10 || opacity > 100) {
+ opacity = 50;
+ }
+ }
+ mDeltaHeight = deltaHeight;
+ mDrawableOpacity = opacity;
}
private void hideAfterDelay() {
@@ -5293,6 +5325,17 @@ public class Editor {
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mCursorControlEnabled) {
+ final int height = Math.max(
+ getPreferredHeight() + mDeltaHeight, mDrawable.getIntrinsicHeight());
+ setMeasuredDimension(getPreferredWidth(), height);
+ return;
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
if (mCursorControlEnabled && FLAG_ENABLE_CURSOR_DRAG) {
// Should only enable touch through when cursor drag is enabled.
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 733a7753568a..970d70cf1fb4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -52,7 +52,6 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -307,6 +306,9 @@ public class ProgressBar extends View {
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
+ // onProgressRefresh() is only called when the progress changes. So we should set
+ // stateDescription during initialization here.
+ super.setStateDescription(formatStateDescription(mProgress));
setSecondaryProgress(a.getInt(
R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
@@ -1599,8 +1601,7 @@ public class ProgressBar extends View {
}
void onProgressRefresh(float scale, boolean fromUser, int progress) {
- if (AccessibilityManager.getInstance(mContext).isEnabled()
- && mCustomStateDescription == null) {
+ if (mCustomStateDescription == null) {
super.setStateDescription(formatStateDescription(mProgress));
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 32d3fef88e81..8ce6ee576b00 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8668,6 +8668,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.initialSelStart = getSelectionStart();
outAttrs.initialSelEnd = getSelectionEnd();
outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
+ outAttrs.setInitialSurroundingText(mText);
return ic;
}
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 969bda9da5a0..42d7892eeffb 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -456,7 +456,7 @@ public class Toast {
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = com.android.internal.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
- params.setFitIgnoreVisibility(true);
+ params.setFitInsetsIgnoringVisibility(true);
params.setTitle("Toast");
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index fa1e498d55b6..1a8e7a713e7a 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -35,6 +35,66 @@ public final class WidgetFlags {
*/
public static final String KEY_ENABLE_CURSOR_CONTROL = "widget__enable_cursor_control";
+ /**
+ * The flag of delta height applies to the insertion handle when cursor control flag is enabled.
+ * The default value is 25.
+ */
+ public static final String INSERTION_HANDLE_DELTA_HEIGHT =
+ "CursorControlFeature__insertion_handle_delta_height";
+
+ /**
+ * The key name used in app core settings for {@link #INSERTION_HANDLE_DELTA_HEIGHT}.
+ */
+ public static final String KEY_INSERTION_HANDLE_DELTA_HEIGHT =
+ "widget__insertion_handle_delta_height";
+
+ /**
+ * The flag of opacity applies to the insertion handle when cursor control flag is enabled.
+ * The opacity value is in the range of {0..100}. The default value is 50.
+ */
+ public static final String INSERTION_HANDLE_OPACITY =
+ "CursorControlFeature__insertion_handle_opacity";
+
+ /**
+ * The key name used in app core settings for {@link #INSERTION_HANDLE_OPACITY}.
+ */
+ public static final String KEY_INSERTION_HANDLE_OPACITY =
+ "widget__insertion_handle_opacity";
+
+ /**
+ * The flag of enabling the new magnifier.
+ */
+ public static final String ENABLE_NEW_MAGNIFIER = "CursorControlFeature__enable_new_magnifier";
+
+ /**
+ * The key name used in app core settings for {@link #ENABLE_NEW_MAGNIFIER}.
+ */
+ public static final String KEY_ENABLE_NEW_MAGNIFIER = "widget__enable_new_magnifier";
+
+ /**
+ * The flag of zoom factor applies to the new magnifier.
+ * The default value is 1.5f.
+ */
+ public static final String MAGNIFIER_ZOOM_FACTOR =
+ "CursorControlFeature__magnifier_zoom_factor";
+
+ /**
+ * The key name used in app core settings for {@link #MAGNIFIER_ZOOM_FACTOR}.
+ */
+ public static final String KEY_MAGNIFIER_ZOOM_FACTOR = "widget__magnifier_zoom_factor";
+
+ /**
+ * The flag of aspect ratio (width/height) applies to the new magnifier.
+ * The default value is 5.5f.
+ */
+ public static final String MAGNIFIER_ASPECT_RATIO =
+ "CursorControlFeature__magnifier_aspect_ratio";
+
+ /**
+ * The key name used in app core settings for {@link #MAGNIFIER_ASPECT_RATIO}.
+ */
+ public static final String KEY_MAGNIFIER_ASPECT_RATIO = "widget__magnifier_aspect_ratio";
+
private WidgetFlags() {
}
}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 08022e983892..b2aa0431251d 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -26,7 +26,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
/**
* Skeletal {@link PagerAdapter} implementation of a work or personal profile page for
@@ -34,6 +36,7 @@ import java.util.Objects;
*/
public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
+ private static final String TAG = "AbstractMultiProfilePagerAdapter";
static final int PROFILE_PERSONAL = 0;
static final int PROFILE_WORK = 1;
@IntDef({PROFILE_PERSONAL, PROFILE_WORK})
@@ -41,10 +44,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
private final Context mContext;
private int mCurrentPage;
+ private OnProfileSelectedListener mOnProfileSelectedListener;
+ private Set<Integer> mLoadedPages;
AbstractMultiProfilePagerAdapter(Context context, int currentPage) {
mContext = Objects.requireNonNull(context);
mCurrentPage = currentPage;
+ mLoadedPages = new HashSet<>();
+ }
+
+ void setOnProfileSelectedListener(OnProfileSelectedListener listener) {
+ mOnProfileSelectedListener = listener;
}
Context getContext() {
@@ -57,15 +67,22 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* page and rebuilds the list.
*/
void setupViewPager(ViewPager viewPager) {
- viewPager.setCurrentItem(mCurrentPage);
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mCurrentPage = position;
- getActiveListAdapter().rebuildList();
+ if (!mLoadedPages.contains(position)) {
+ getActiveListAdapter().rebuildList();
+ mLoadedPages.add(position);
+ }
+ if (mOnProfileSelectedListener != null) {
+ mOnProfileSelectedListener.onProfileSelected(position);
+ }
}
});
viewPager.setAdapter(this);
+ viewPager.setCurrentItem(mCurrentPage);
+ mLoadedPages.add(mCurrentPage);
}
@Override
@@ -90,7 +107,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
return mCurrentPage;
}
- UserHandle getCurrentUserHandle() {
+ @VisibleForTesting
+ public UserHandle getCurrentUserHandle() {
return getActiveListAdapter().mResolverListController.getUserHandle();
}
@@ -135,7 +153,8 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* <p>This method is meant to be implemented with an implementation-specific return type
* depending on the adapter type.
*/
- abstract Object getAdapterForIndex(int pageIndex);
+ @VisibleForTesting
+ public abstract Object getAdapterForIndex(int pageIndex);
@VisibleForTesting
public abstract ResolverListAdapter getActiveListAdapter();
@@ -152,7 +171,9 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
abstract Object getCurrentRootAdapter();
- abstract ViewGroup getCurrentAdapterView();
+ abstract ViewGroup getActiveAdapterView();
+
+ abstract @Nullable ViewGroup getInactiveAdapterView();
protected class ProfileDescriptor {
final ViewGroup rootView;
@@ -160,4 +181,15 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
this.rootView = rootView;
}
}
+
+ public interface OnProfileSelectedListener {
+ /**
+ * Callback for when the user changes the active tab from personal to work or vice versa.
+ * <p>This callback is only called when the intent resolver or share sheet shows
+ * the work and personal profiles.
+ * @param profileIndex {@link #PROFILE_PERSONAL} if the personal profile was selected or
+ * {@link #PROFILE_WORK} if the work profile was selected.
+ */
+ void onProfileSelected(int profileIndex);
+ }
} \ No newline at end of file
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 9532faecb4df..8bbc343fa4ca 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -508,7 +508,6 @@ public class ChooserActivity extends ResolverActivity implements
protected void onCreate(Bundle savedInstanceState) {
final long intentReceivedTime = System.currentTimeMillis();
// This is the only place this value is being set. Effectively final.
- //TODO(arangelov) - should there be a mIsAppPredictorComponentAvailable flag for work tab?
mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable();
mIsSuccessfullySelected = false;
@@ -689,29 +688,6 @@ public class ChooserActivity extends ResolverActivity implements
mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
}
- final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header);
- final float defaultElevation = chooserHeader.getElevation();
- final float chooserHeaderScrollElevation =
- getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
-
- mChooserMultiProfilePagerAdapter.getCurrentAdapterView().addOnScrollListener(
- new RecyclerView.OnScrollListener() {
- public void onScrollStateChanged(RecyclerView view, int scrollState) {
- }
-
- public void onScrolled(RecyclerView view, int dx, int dy) {
- if (view.getChildCount() > 0) {
- View child = view.getLayoutManager().findViewByPosition(0);
- if (child == null || child.getTop() < 0) {
- chooserHeader.setElevation(chooserHeaderScrollElevation);
- return;
- }
- }
-
- chooserHeader.setElevation(defaultElevation);
- }
- });
-
mResolverDrawerLayout.setOnCollapsedChangedListener(
new ResolverDrawerLayout.OnCollapsedChangedListener() {
@@ -1330,8 +1306,8 @@ public class ChooserActivity extends ResolverActivity implements
}
@Override
- public void onPrepareAdapterView(ResolverListAdapter adapter) {
- mChooserMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
+ public void addUseDifferentAppLabelIfNecessary(ResolverListAdapter adapter) {
+ mChooserMultiProfilePagerAdapter.getActiveAdapterView().setVisibility(View.VISIBLE);
if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(
/* origTarget */ null,
@@ -2202,7 +2178,7 @@ public class ChooserActivity extends ResolverActivity implements
if (mChooserMultiProfilePagerAdapter == null) {
return;
}
- RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getCurrentAdapterView();
+ RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getActiveAdapterView();
ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter();
if (gridAdapter == null || recyclerView == null) {
return;
@@ -2328,6 +2304,8 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void onListRebuilt(ResolverListAdapter listAdapter) {
+ setupScrollListener();
+
ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter;
if (chooserListAdapter.mDisplayList == null
|| chooserListAdapter.mDisplayList.isEmpty()) {
@@ -2368,6 +2346,34 @@ public class ChooserActivity extends ResolverActivity implements
}
}
+ private void setupScrollListener() {
+ if (mResolverDrawerLayout == null) {
+ return;
+ }
+ final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header);
+ final float defaultElevation = chooserHeader.getElevation();
+ final float chooserHeaderScrollElevation =
+ getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
+
+ mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ public void onScrollStateChanged(RecyclerView view, int scrollState) {
+ }
+
+ public void onScrolled(RecyclerView view, int dx, int dy) {
+ if (view.getChildCount() > 0) {
+ View child = view.getLayoutManager().findViewByPosition(0);
+ if (child == null || child.getTop() < 0) {
+ chooserHeader.setElevation(chooserHeaderScrollElevation);
+ return;
+ }
+ }
+
+ chooserHeader.setElevation(defaultElevation);
+ }
+ });
+ }
+
@Override // ChooserListCommunicator
public boolean isSendAction(Intent targetIntent) {
if (targetIntent == null) {
@@ -2475,7 +2481,8 @@ public class ChooserActivity extends ResolverActivity implements
* row level by this adapter but not on the item level. Individual targets within the row are
* handled by {@link ChooserListAdapter}
*/
- final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ @VisibleForTesting
+ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ChooserListAdapter mChooserListAdapter;
private final LayoutInflater mLayoutInflater;
@@ -2905,7 +2912,7 @@ public class ChooserActivity extends ResolverActivity implements
if (mDirectShareViewHolder != null && canExpandDirectShare) {
mDirectShareViewHolder.handleScroll(
- mChooserMultiProfilePagerAdapter.getCurrentAdapterView(), y, oldy,
+ mChooserMultiProfilePagerAdapter.getActiveAdapterView(), y, oldy,
getMaxTargetsPerRow());
}
}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index a8a676d03971..6ff844a2eaae 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -246,11 +246,6 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
@Override
- public boolean shouldGetResolvedFilter() {
- return true;
- }
-
- @Override
public int getCount() {
return getRankedTargetCount() + getAlphaTargetCount()
+ getSelectableServiceTargetCount() + getCallerTargetCount();
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 7d856e1b945d..1c52d0e8f9f1 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -16,6 +16,7 @@
package com.android.internal.app;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -77,7 +78,8 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
@Override
- ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) {
+ @VisibleForTesting
+ public ChooserActivity.ChooserGridAdapter getAdapterForIndex(int pageIndex) {
return mItems[pageIndex].chooserGridAdapter;
}
@@ -121,10 +123,19 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
@Override
- RecyclerView getCurrentAdapterView() {
+ RecyclerView getActiveAdapterView() {
return getListViewForIndex(getCurrentPage());
}
+ @Override
+ @Nullable
+ RecyclerView getInactiveAdapterView() {
+ if (getCount() == 1) {
+ return null;
+ }
+ return getListViewForIndex(1 - getCurrentPage());
+ }
+
class ChooserProfileDescriptor extends ProfileDescriptor {
private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index be2d1d60e9a2..f3b6d292623d 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,6 +26,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractionSessionListener;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.service.voice.IVoiceInteractionService;
@@ -72,8 +73,8 @@ interface IVoiceInteractionManagerService {
*/
SoundTrigger.ModuleProperties getDspModuleProperties(in IVoiceInteractionService service);
/**
- * Indicates if there's a keyphrase sound model available for the given keyphrase ID.
- * This performs the check for the current user.
+ * Indicates if there's a keyphrase sound model available for the given keyphrase ID and the
+ * user ID of the caller.
*
* @param service The current VoiceInteractionService.
* @param keyphraseId The unique identifier for the keyphrase.
@@ -82,6 +83,18 @@ interface IVoiceInteractionManagerService {
boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
String bcp47Locale);
/**
+ * Generates KeyphraseMetadata for an enrolled sound model based on keyphrase string, locale,
+ * and the user ID of the caller.
+ *
+ * @param service The current VoiceInteractionService
+ * @param keyphrase Keyphrase text associated with the enrolled model
+ * @param bcp47Locale The BCP47 language tag for the keyphrase's locale.
+ * @return The metadata for the enrolled voice model bassed on the passed in parameters. Null if
+ * no matching voice model exists.
+ */
+ KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service,
+ String keyphrase, String bcp47Locale);
+ /**
* Starts a recognition for the given keyphrase.
*/
int startRecognition(in IVoiceInteractionService service, int keyphraseId,
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index b2417b2e79cc..68d6e03f654c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -59,6 +59,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -67,9 +68,12 @@ import android.view.WindowInsets;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Button;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Space;
+import android.widget.TabHost;
+import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.Toast;
@@ -82,6 +86,7 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.widget.ResolverDrawerLayout;
+import com.android.internal.widget.ViewPager;
import java.util.ArrayList;
import java.util.Arrays;
@@ -147,7 +152,10 @@ public class ResolverActivity extends Activity implements
/**
* TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
*/
- static final boolean ENABLE_TABBED_VIEW = false;
+ @VisibleForTesting
+ public static boolean ENABLE_TABBED_VIEW = false;
+ private static final String TAB_TAG_PERSONAL = "personal";
+ private static final String TAB_TAG_WORK = "work";
private final PackageMonitor mPackageMonitor = createPackageMonitor();
@@ -418,12 +426,16 @@ public class ResolverActivity extends Activity implements
Intent[] initialIntents,
List<ResolveInfo> rList,
boolean filterLastUsed) {
+ // We only show the default app for the profile of the current user. The filterLastUsed
+ // flag determines whether to show a default app and that app is not shown in the
+ // resolver list. So filterLastUsed should be false for the other profile.
ResolverListAdapter personalAdapter = createResolverListAdapter(
/* context */ this,
/* payloadIntents */ mIntents,
initialIntents,
rList,
- filterLastUsed,
+ (filterLastUsed && UserHandle.myUserId()
+ == getPersonalProfileUserHandle().getIdentifier()),
mUseLayoutForBrowsables,
/* userHandle */ getPersonalProfileUserHandle());
ResolverListAdapter workAdapter = createResolverListAdapter(
@@ -431,7 +443,8 @@ public class ResolverActivity extends Activity implements
/* payloadIntents */ mIntents,
initialIntents,
rList,
- filterLastUsed,
+ (filterLastUsed && UserHandle.myUserId()
+ == getWorkProfileUserHandle().getIdentifier()),
mUseLayoutForBrowsables,
/* userHandle */ getWorkProfileUserHandle());
return new ResolverMultiProfilePagerAdapter(
@@ -495,12 +508,12 @@ public class ResolverActivity extends Activity implements
mFooterSpacer = new Space(getApplicationContext());
} else {
((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
- .getCurrentAdapterView().removeFooterView(mFooterSpacer);
+ .getActiveAdapterView().removeFooterView(mFooterSpacer);
}
mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
mSystemWindowInsets.bottom));
((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
- .getCurrentAdapterView().addFooterView(mFooterSpacer);
+ .getActiveAdapterView().addFooterView(mFooterSpacer);
}
protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
@@ -817,7 +830,7 @@ public class ResolverActivity extends Activity implements
public void onButtonClick(View v) {
final int id = v.getId();
- ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ ListView listView = (ListView) mMultiProfilePagerAdapter.getActiveAdapterView();
ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
int which = currentListAdapter.hasFilteredItem()
? currentListAdapter.getFilteredPosition()
@@ -898,7 +911,10 @@ public class ResolverActivity extends Activity implements
@Override // ResolverListCommunicator
public void onPostListReady(ResolverListAdapter listAdapter) {
- setHeader();
+ if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
+ == UserHandle.myUserId()) {
+ setHeader();
+ }
resetButtonBar();
onListRebuilt(listAdapter);
}
@@ -913,6 +929,9 @@ public class ResolverActivity extends Activity implements
finish();
}
}
+
+ final ItemClickListener listener = new ItemClickListener();
+ setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener);
}
protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
@@ -1094,6 +1113,7 @@ public class ResolverActivity extends Activity implements
return true;
}
+ @VisibleForTesting
public void safelyStartActivity(TargetInfo cti) {
// We're dispatching intents that might be coming from legacy apps, so
// don't kill ourselves.
@@ -1222,9 +1242,6 @@ public class ResolverActivity extends Activity implements
+ "cannot be null.");
}
boolean rebuildCompleted = mMultiProfilePagerAdapter.getActiveListAdapter().rebuildList();
- if (mMultiProfilePagerAdapter.getInactiveListAdapter() != null) {
- mMultiProfilePagerAdapter.getInactiveListAdapter().rebuildList();
- }
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
@@ -1272,45 +1289,99 @@ public class ResolverActivity extends Activity implements
}
}
- setupViewVisibilities(count);
+ setupViewVisibilities();
+
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ setupProfileTabs();
+ }
+
return false;
}
- private void setupViewVisibilities(int count) {
- if (count == 0
- && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0) {
- final TextView emptyView = findViewById(R.id.empty);
- emptyView.setVisibility(View.VISIBLE);
- findViewById(R.id.profile_pager).setVisibility(View.GONE);
- } else {
- onPrepareAdapterView(mMultiProfilePagerAdapter.getActiveListAdapter());
+ private void setupProfileTabs() {
+ TabHost tabHost = findViewById(R.id.profile_tabhost);
+ tabHost.setup();
+ ViewPager viewPager = findViewById(R.id.profile_pager);
+ TabHost.TabSpec tabSpec = tabHost.newTabSpec(TAB_TAG_PERSONAL)
+ .setContent(R.id.profile_pager)
+ .setIndicator(getString(R.string.resolver_personal_tab));
+ tabHost.addTab(tabSpec);
+
+ tabSpec = tabHost.newTabSpec(TAB_TAG_WORK)
+ .setContent(R.id.profile_pager)
+ .setIndicator(getString(R.string.resolver_work_tab));
+ tabHost.addTab(tabSpec);
+
+ TabWidget tabWidget = tabHost.getTabWidget();
+ tabWidget.setVisibility(View.VISIBLE);
+ resetTabsHeaderStyle(tabWidget);
+ updateActiveTabStyle(tabHost);
+
+ tabHost.setOnTabChangedListener(tabId -> {
+ resetTabsHeaderStyle(tabWidget);
+ updateActiveTabStyle(tabHost);
+ if (TAB_TAG_PERSONAL.equals(tabId)) {
+ viewPager.setCurrentItem(0);
+ } else {
+ viewPager.setCurrentItem(1);
+ }
+ setupViewVisibilities();
+ });
+
+ viewPager.setVisibility(View.VISIBLE);
+ tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
+ mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab);
+ }
+
+ private void resetTabsHeaderStyle(TabWidget tabWidget) {
+ for (int i = 0; i < tabWidget.getChildCount(); i++) {
+ TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title);
+ title.setTextColor(getColor(R.color.resolver_tabs_inactive_color));
+ title.setAllCaps(false);
+ }
+ }
+
+ private void updateActiveTabStyle(TabHost tabHost) {
+ TextView title = tabHost.getTabWidget().getChildAt(tabHost.getCurrentTab())
+ .findViewById(android.R.id.title);
+ title.setTextColor(getColor(R.color.resolver_tabs_active_color));
+ }
+
+ private void setupViewVisibilities() {
+ int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();
+ boolean shouldShowEmptyState = count == 0
+ && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0;
+ //TODO(arangelov): Handle empty state
+ if (!shouldShowEmptyState) {
+ addUseDifferentAppLabelIfNecessary(mMultiProfilePagerAdapter.getActiveListAdapter());
}
}
/**
- * Prepare the scrollable view which consumes data in the list adapter.
+ * Add a label to signify that the user can pick a different app.
* @param adapter The adapter used to provide data to item views.
*/
- public void onPrepareAdapterView(ResolverListAdapter adapter) {
- mMultiProfilePagerAdapter.getCurrentAdapterView().setVisibility(View.VISIBLE);
+ public void addUseDifferentAppLabelIfNecessary(ResolverListAdapter adapter) {
final boolean useHeader = adapter.hasFilteredItem();
- final ListView listView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
- final ItemClickListener listener = new ItemClickListener();
+ if (useHeader) {
+ FrameLayout stub = findViewById(R.id.stub);
+ stub.setVisibility(View.VISIBLE);
+ TextView textView = (TextView) LayoutInflater.from(this).inflate(
+ R.layout.resolver_different_item_header, null, false);
+ if (ENABLE_TABBED_VIEW) {
+ textView.setGravity(Gravity.CENTER);
+ }
+ stub.addView(textView);
+ }
+ }
+
+ private void setupAdapterListView(ListView listView, ItemClickListener listener) {
listView.setOnItemClickListener(listener);
listView.setOnItemLongClickListener(listener);
if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
}
-
- // In case this method is called again (due to activity recreation), avoid adding a new
- // header if one is already present.
- if (useHeader && listView.getHeaderViewsCount() == 0) {
- listView.setHeaderDividersEnabled(true);
- listView.addHeaderView(LayoutInflater.from(this).inflate(
- R.layout.resolver_different_item_header, listView, false),
- null, false);
- }
}
/**
@@ -1378,7 +1449,7 @@ public class ResolverActivity extends Activity implements
}
// When the items load in, if an item was already selected, enable the buttons
- ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ ListView currentAdapterView = (ListView) mMultiProfilePagerAdapter.getActiveAdapterView();
if (currentAdapterView != null
&& currentAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
setAlwaysButtonEnabled(true, currentAdapterView.getCheckedItemPosition(), true);
@@ -1388,8 +1459,18 @@ public class ResolverActivity extends Activity implements
@Override // ResolverListCommunicator
public boolean useLayoutWithDefault() {
- return mSupportsAlwaysUseOption
- && mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem();
+ // We only use the default app layout when the profile of the active user has a
+ // filtered item. We always show the same default app even in the inactive user profile.
+ boolean currentUserAdapterHasFilteredItem;
+ if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
+ == UserHandle.myUserId()) {
+ currentUserAdapterHasFilteredItem =
+ mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem();
+ } else {
+ currentUserAdapterHasFilteredItem =
+ mMultiProfilePagerAdapter.getInactiveListAdapter().hasFilteredItem();
+ }
+ return mSupportsAlwaysUseOption && currentUserAdapterHasFilteredItem;
}
/**
@@ -1494,9 +1575,8 @@ public class ResolverActivity extends Activity implements
.resolveInfoForPosition(position, true) == null) {
return;
}
-
ListView currentAdapterView =
- (ListView) mMultiProfilePagerAdapter.getCurrentAdapterView();
+ (ListView) mMultiProfilePagerAdapter.getActiveAdapterView();
final int checkedPos = currentAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index ef7a347cf7be..d227ec5c1b38 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -193,7 +193,8 @@ public class ResolverListAdapter extends BaseAdapter {
mBaseResolveList);
} else {
currentResolveList = mUnfilteredResolveList =
- mResolverListController.getResolversForIntent(shouldGetResolvedFilter(),
+ mResolverListController.getResolversForIntent(
+ /* shouldGetResolvedFilter= */ true,
mResolverListCommunicator.shouldGetActivityMetadata(),
mIntents);
if (currentResolveList == null) {
@@ -363,10 +364,6 @@ public class ResolverListAdapter extends BaseAdapter {
}
}
- public boolean shouldGetResolvedFilter() {
- return mFilterLastUsed;
- }
-
private void addResolveInfoWithAlternates(ResolvedComponentInfo rci) {
final int count = rci.getCount();
final Intent intent = rci.getIntentAt(0);
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index abd3eb2453df..0bfe9eb04d28 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -133,7 +133,8 @@ public class ResolverListController {
return resolvedComponents;
}
- UserHandle getUserHandle() {
+ @VisibleForTesting
+ public UserHandle getUserHandle() {
return mUserHandle;
}
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index d72c52bfe6b6..567ed74670bf 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -16,6 +16,7 @@
package com.android.internal.app;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -81,7 +82,8 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
}
@Override
- ResolverListAdapter getAdapterForIndex(int pageIndex) {
+ @VisibleForTesting
+ public ResolverListAdapter getAdapterForIndex(int pageIndex) {
return mItems[pageIndex].resolverListAdapter;
}
@@ -106,10 +108,19 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
}
@Override
- ListView getCurrentAdapterView() {
+ ListView getActiveAdapterView() {
return getListViewForIndex(getCurrentPage());
}
+ @Override
+ @Nullable
+ ViewGroup getInactiveAdapterView() {
+ if (getCount() == 1) {
+ return null;
+ }
+ return getListViewForIndex(1 - getCurrentPage());
+ }
+
class ResolverProfileDescriptor extends ProfileDescriptor {
private ResolverListAdapter resolverListAdapter;
final ListView listView;
diff --git a/core/java/com/android/internal/app/WrapHeightViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index b017bb44d751..8ec94f159725 100644
--- a/core/java/com/android/internal/app/WrapHeightViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -18,39 +18,36 @@ package com.android.internal.app;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.ViewPager;
/**
- * A {@link ViewPager} which wraps around its first child's height.
+ * A {@link ViewPager} which wraps around its first child's height and has swiping disabled.
* <p>Normally {@link ViewPager} instances expand their height to cover all remaining space in
* the layout.
- * <p>This class is used for the intent resolver picker's tabbed view to maintain
- * consistency with the previous behavior.
+ * <p>This class is used for the intent resolver and share sheet's tabbed view.
*/
-public class WrapHeightViewPager extends ViewPager {
+public class ResolverViewPager extends ViewPager {
- public WrapHeightViewPager(Context context) {
+ public ResolverViewPager(Context context) {
super(context);
}
- public WrapHeightViewPager(Context context, AttributeSet attrs) {
+ public ResolverViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
- public WrapHeightViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+ public ResolverViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
- public WrapHeightViewPager(Context context, AttributeSet attrs,
+ public ResolverViewPager(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
- // TODO(arangelov): When we have multiple pages, the height should wrap to the currently
- // displayed page. Investigate whether onMeasure is called when changing a page, and instead
- // of getChildAt(0), use the currently displayed one.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -68,4 +65,14 @@ public class WrapHeightViewPager extends ViewPager {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b3548b8c82f8..580c1f00d788 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12644,7 +12644,6 @@ public class BatteryStatsImpl extends BatteryStats {
/*@hide */
public WifiBatteryStats getWifiBatteryStats() {
- WifiBatteryStats s = new WifiBatteryStats();
final int which = STATS_SINCE_CHARGED;
final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
final ControllerActivityCounter counter = getWifiControllerActivity();
@@ -12675,24 +12674,16 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
}
- s.setLoggingDurationMillis(computeBatteryRealtime(rawRealTime, which) / 1000);
- s.setKernelActiveTimeMillis(getWifiActiveTime(rawRealTime, which) / 1000);
- s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which));
- s.setNumBytesTx(getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which));
- s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which));
- s.setNumBytesRx(getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which));
- s.setSleepTimeMillis(sleepTimeMs);
- s.setIdleTimeMillis(idleTimeMs);
- s.setRxTimeMillis(rxTimeMs);
- s.setTxTimeMillis(txTimeMs);
- s.setScanTimeMillis(scanTimeMs);
- s.setEnergyConsumedMaMillis(energyConsumedMaMs);
- s.setNumAppScanRequest(numAppScanRequest);
- s.setTimeInStateMillis(timeInStateMs);
- s.setTimeInSupplicantStateMillis(timeInSupplStateMs);
- s.setTimeInRxSignalStrengthLevelMillis(timeSignalStrengthTimeMs);
- s.setMonitoredRailChargeConsumedMaMillis(monitoredRailChargeConsumedMaMs);
- return s;
+ return new WifiBatteryStats(
+ computeBatteryRealtime(rawRealTime, which) / 1000,
+ getWifiActiveTime(rawRealTime, which) / 1000,
+ getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which),
+ getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which),
+ getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which),
+ getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which),
+ sleepTimeMs, scanTimeMs, idleTimeMs, rxTimeMs, txTimeMs, energyConsumedMaMs,
+ numAppScanRequest, timeInStateMs, timeSignalStrengthTimeMs, timeInSupplStateMs,
+ monitoredRailChargeConsumedMaMs);
}
/*@hide */
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 5e3c5dfe6bdc..7a9b6590d56b 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -753,6 +753,8 @@ public class ProcessCpuTracker {
proto.write(CpuUsageProto.Load.LOAD15, mLoad15);
proto.end(currentLoadToken);
+ buildWorkingProcs();
+
proto.write(CpuUsageProto.NOW, now);
proto.write(CpuUsageProto.LAST_SAMPLE_TIME, mLastSampleTime);
proto.write(CpuUsageProto.CURRENT_SAMPLE_TIME, mCurrentSampleTime);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index a6637a2fb601..8412b846b2a6 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -68,6 +68,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Build.VERSION_CODES;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
@@ -282,6 +283,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private Insets mLastBackgroundInsets = Insets.NONE;
private boolean mDrawLegacyNavigationBarBackground;
+ /**
+ * Whether the app targets an SDK that uses the new insets APIs.
+ */
+ private boolean mUseNewInsetsApi;
+
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
super(context);
@@ -311,6 +317,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
initResizingPaints();
mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
+ mUseNewInsetsApi = context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.R;
}
void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
@@ -1174,20 +1181,24 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
// Note: We don't need to check for IN_SCREEN or INSET_DECOR because unlike the status bar,
// these flags wouldn't make the window draw behind the navigation bar, unless
// LAYOUT_HIDE_NAVIGATION was set.
+ //
+ // Note: Once the app targets R+, we no longer do this logic because we can't rely on
+ // SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION to indicate whether the app wants to handle it by
+ // themselves.
boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
|| !(state == null || state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
boolean forceConsumingNavBar = (mForceWindowDrawsBarBackgrounds
&& (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
- && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
&& !hideNavigation)
|| (mLastShouldAlwaysConsumeSystemBars && hideNavigation);
boolean consumingNavBar =
((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
&& (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
- && (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) != 0
- && !hideNavigation)
+ && !hideNavigation
+ // TODO IME wrap_content windows need to have margin to work properly
+ && (!mUseNewInsetsApi || isImeWindow))
|| forceConsumingNavBar;
// If we didn't request fullscreen layout, but we still got it because of the
@@ -1200,16 +1211,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0
&& (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0
&& (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0
- && (attrs.getFitWindowInsetsTypes() & Type.statusBars()) != 0
&& mForceWindowDrawsBarBackgrounds
&& mLastTopInset != 0
|| (mLastShouldAlwaysConsumeSystemBars && fullscreen);
- int sides = attrs.getFitWindowInsetsSides();
- int consumedTop = consumingStatusBar && (sides & Side.TOP) != 0 ? mLastTopInset : 0;
- int consumedRight = consumingNavBar && (sides & Side.RIGHT) != 0 ? mLastRightInset : 0;
- int consumedBottom = consumingNavBar && (sides & Side.BOTTOM) != 0 ? mLastBottomInset : 0;
- int consumedLeft = consumingNavBar && (sides & Side.LEFT) != 0 ? mLastLeftInset : 0;
+ int consumedTop = consumingStatusBar ? mLastTopInset : 0;
+ int consumedRight = consumingNavBar ? mLastRightInset : 0;
+ int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
+ int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
if (mContentRoot != null
&& mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 4abd39797ba0..95558c31e671 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -17,8 +17,11 @@
package com.android.internal.policy;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -30,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -43,6 +48,7 @@ import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
@@ -66,6 +72,7 @@ import android.transition.TransitionSet;
import android.util.AndroidRuntimeException;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
@@ -307,6 +314,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
/** @see ViewRootImpl#mActivityConfigCallback */
private ActivityConfigCallback mActivityConfigCallback;
+ private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -2092,6 +2101,34 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
/** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
void onViewRootImplSet(ViewRootImpl viewRoot) {
viewRoot.setActivityConfigCallback(mActivityConfigCallback);
+ if (mPendingOnContentApplyWindowInsetsListener != null) {
+ viewRoot.setOnContentApplyWindowInsetsListener(
+ mPendingOnContentApplyWindowInsetsListener);
+ mPendingOnContentApplyWindowInsetsListener = null;
+ } else {
+ viewRoot.setOnContentApplyWindowInsetsListener(
+ createDefaultContentWindowInsetsListener());
+ }
+ }
+
+ private OnContentApplyWindowInsetsListener createDefaultContentWindowInsetsListener() {
+ return insets -> {
+ if ((getDecorView().getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) {
+ return new Pair<>(Insets.NONE, insets);
+ }
+
+ boolean includeIme = (getAttributes().softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE;
+ Insets insetsToApply;
+ if (ViewRootImpl.sNewInsetsMode == 0) {
+ insetsToApply = insets.getSystemWindowInsets();
+ } else {
+ insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0));
+ }
+ insets = insets.inset(insetsToApply);
+ return new Pair<>(insetsToApply,
+ insets.inset(insetsToApply).consumeSystemWindowInsets());
+ };
}
static private final String FOCUSED_ID_TAG = "android:focusedViewId";
@@ -2344,6 +2381,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
+ getAttributes().setFitInsetsSides(0);
+ getAttributes().setFitInsetsTypes(0);
}
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
@@ -2656,7 +2695,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
- mDecor.makeOptionalFitsSystemWindows();
+ mDecor.makeFrameworkOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
@@ -3853,4 +3892,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public List<Rect> getSystemGestureExclusionRects() {
return getViewRootImpl().getRootSystemGestureExclusionRects();
}
+
+ @Override
+ public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ ViewRootImpl impl = getViewRootImpl();
+ if (impl != null) {
+ impl.setOnContentApplyWindowInsetsListener(listener);
+ } else {
+ mPendingOnContentApplyWindowInsetsListener = listener;
+ }
+ }
+
+ @Override
+ public void resetOnContentApplyWindowInsetsListener() {
+ setOnContentApplyWindowInsetsListener(createDefaultContentWindowInsetsListener());
+ }
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 8cad5a0d1d09..7cff90bbf437 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -6,7 +6,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -14,6 +18,7 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
+import android.view.WindowManager;
import java.util.function.Consumer;
@@ -38,9 +43,9 @@ public class ScreenshotHelper {
* is recommended for general use.
*
* @param screenshotType The type of screenshot, for example either
- * {@link android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN}
+ * {@link android.view.WindowManager#TAKE_SCREENSHOT_FULLSCREEN}
* or
- * {@link android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION}
+ * {@link android.view.WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
* @param hasStatus {@code true} if the status bar is currently showing. {@code false}
* if
* not.
@@ -65,9 +70,9 @@ public class ScreenshotHelper {
* is recommended for general use.
*
* @param screenshotType The type of screenshot, for example either
- * {@link android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN}
+ * {@link android.view.WindowManager#TAKE_SCREENSHOT_FULLSCREEN}
* or
- * {@link android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION}
+ * {@link android.view.WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
* @param hasStatus {@code true} if the status bar is currently showing. {@code false}
* if
* not.
@@ -84,6 +89,40 @@ public class ScreenshotHelper {
public void takeScreenshot(final int screenshotType, final boolean hasStatus,
final boolean hasNav, long timeoutMs, @NonNull Handler handler,
@Nullable Consumer<Uri> completionConsumer) {
+ takeScreenshot(screenshotType, hasStatus, hasNav, timeoutMs, handler, null,
+ completionConsumer
+ );
+ }
+
+ /**
+ * Request that provided image be handled as if it was a screenshot.
+ *
+ * @param screenshot The bitmap to treat as the screen shot.
+ * @param boundsInScreen The bounds in screen coordinates that the bitmap orginated from.
+ * @param insets The insets that the image was shown with, inside the screenbounds.
+ * @param taskId The taskId of the task that the screen shot was taken of.
+ * @param handler A handler used in case the screenshot times out
+ * @param completionConsumer Consumes `false` if a screenshot was not taken, and `true` if the
+ * screenshot was taken.
+ */
+ public void provideScreenshot(@NonNull Bitmap screenshot, @NonNull Rect boundsInScreen,
+ @NonNull Insets insets, int taskId, @NonNull Handler handler,
+ @Nullable Consumer<Uri> completionConsumer) {
+ Bundle imageBundle = new Bundle();
+ imageBundle.putParcelable(WindowManager.PARCEL_KEY_SCREENSHOT_BITMAP, screenshot);
+ imageBundle.putParcelable(WindowManager.PARCEL_KEY_SCREENSHOT_BOUNDS, boundsInScreen);
+ imageBundle.putParcelable(WindowManager.PARCEL_KEY_SCREENSHOT_INSETS, insets);
+ imageBundle.putInt(WindowManager.PARCEL_KEY_SCREENSHOT_TASK_ID, taskId);
+
+ takeScreenshot(
+ WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE,
+ false, false, // ignored when image bundle is set
+ SCREENSHOT_TIMEOUT_MS, handler, imageBundle, completionConsumer);
+ }
+
+ private void takeScreenshot(final int screenshotType, final boolean hasStatus,
+ final boolean hasNav, long timeoutMs, @NonNull Handler handler,
+ @Nullable Bundle providedImage, @Nullable Consumer<Uri> completionConsumer) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
return;
@@ -139,6 +178,10 @@ public class ScreenshotHelper {
msg.arg1 = hasStatus ? 1 : 0;
msg.arg2 = hasNav ? 1 : 0;
+ if (screenshotType == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ msg.setData(providedImage);
+ }
+
try {
messenger.send(msg);
} catch (RemoteException e) {
diff --git a/core/jni/android_media_AudioEffectDescriptor.cpp b/core/jni/android_media_AudioEffectDescriptor.cpp
index 5175a05c4c3b..37d8114052b8 100644
--- a/core/jni/android_media_AudioEffectDescriptor.cpp
+++ b/core/jni/android_media_AudioEffectDescriptor.cpp
@@ -39,17 +39,21 @@ jint convertAudioEffectDescriptorFromNative(JNIEnv* env, jobject* jDescriptor,
jstring jImplementor;
char str[EFFECT_STRING_LEN_MAX];
- if ((nDescriptor->flags & EFFECT_FLAG_TYPE_MASK)
- == EFFECT_FLAG_TYPE_AUXILIARY) {
- jConnect = env->NewStringUTF("Auxiliary");
- } else if ((nDescriptor->flags & EFFECT_FLAG_TYPE_MASK)
- == EFFECT_FLAG_TYPE_INSERT) {
- jConnect = env->NewStringUTF("Insert");
- } else if ((nDescriptor->flags & EFFECT_FLAG_TYPE_MASK)
- == EFFECT_FLAG_TYPE_PRE_PROC) {
- jConnect = env->NewStringUTF("Pre Processing");
- } else {
- return (jint) AUDIO_JAVA_BAD_VALUE;
+ switch (nDescriptor->flags & EFFECT_FLAG_TYPE_MASK) {
+ case EFFECT_FLAG_TYPE_AUXILIARY:
+ jConnect = env->NewStringUTF("Auxiliary");
+ break;
+ case EFFECT_FLAG_TYPE_INSERT:
+ jConnect = env->NewStringUTF("Insert");
+ break;
+ case EFFECT_FLAG_TYPE_PRE_PROC:
+ jConnect = env->NewStringUTF("Pre Processing");
+ break;
+ case EFFECT_FLAG_TYPE_POST_PROC:
+ jConnect = env->NewStringUTF("Post Processing");
+ break;
+ default:
+ return (jint)AUDIO_JAVA_BAD_VALUE;
}
AudioEffect::guidToString(&nDescriptor->type, str, EFFECT_STRING_LEN_MAX);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index e266fe623947..0156e23e94b6 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -307,6 +307,43 @@ static int _check_AudioSystem_Command(const char* caller, status_t status)
return kAudioStatusError;
}
+static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
+ jobjectArray deviceAddresses,
+ Vector<AudioDeviceTypeAddr> &audioDeviceTypeAddrVector) {
+ if (deviceTypes == nullptr || deviceAddresses == nullptr) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ jsize deviceCount = env->GetArrayLength(deviceTypes);
+ if (deviceCount == 0 || deviceCount != env->GetArrayLength(deviceAddresses)) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ // retrieve all device types
+ std::vector<audio_devices_t> deviceTypesVector;
+ jint *typesPtr = nullptr;
+ typesPtr = env->GetIntArrayElements(deviceTypes, 0);
+ if (typesPtr == nullptr) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ for (jint i = 0; i < deviceCount; i++) {
+ deviceTypesVector.push_back((audio_devices_t)typesPtr[i]);
+ }
+ // check each address is a string and add device type/address to list
+ jclass stringClass = FindClassOrDie(env, "java/lang/String");
+ for (jint i = 0; i < deviceCount; i++) {
+ jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
+ if (!env->IsInstanceOf(addrJobj, stringClass)) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ const char *address = env->GetStringUTFChars((jstring)addrJobj, NULL);
+ AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
+ audioDeviceTypeAddrVector.add(dev);
+ env->ReleaseStringUTFChars((jstring)addrJobj, address);
+ }
+ env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
+
+ return (jint)NO_ERROR;
+}
+
static jint
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
@@ -1905,6 +1942,10 @@ static jint convertAudioMixToNative(JNIEnv *env,
nCriterion.mValue.mUid = env->GetIntField(jCriterion,
gAudioMixMatchCriterionFields.mIntProp);
break;
+ case RULE_MATCH_USERID:
+ nCriterion.mValue.mUserId =
+ env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
+ break;
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
@@ -1990,39 +2031,11 @@ exit:
static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) {
- if (deviceTypes == nullptr || deviceAddresses == nullptr) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
- }
- jsize nb = env->GetArrayLength(deviceTypes);
- if (nb == 0 || nb != env->GetArrayLength(deviceAddresses)) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
- }
- // retrieve all device types
- std::vector<audio_devices_t> deviceTypesVector;
- jint* typesPtr = nullptr;
- typesPtr = env->GetIntArrayElements(deviceTypes, 0);
- if (typesPtr == nullptr) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
- }
- for (jint i = 0; i < nb; i++) {
- deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
- }
-
- // check each address is a string and add device type/address to list for device affinity
Vector<AudioDeviceTypeAddr> deviceVector;
- jclass stringClass = FindClassOrDie(env, "java/lang/String");
- for (jint i = 0; i < nb; i++) {
- jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
- if (!env->IsInstanceOf(addrJobj, stringClass)) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
- }
- const char* address = env->GetStringUTFChars((jstring) addrJobj, NULL);
- AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
- deviceVector.add(dev);
- env->ReleaseStringUTFChars((jstring) addrJobj, address);
+ jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector);
+ if (results != NO_ERROR) {
+ return results;
}
- env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
-
status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
return (jint) nativeToJavaStatus(status);
}
@@ -2033,6 +2046,23 @@ static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, job
return (jint) nativeToJavaStatus(status);
}
+static jint android_media_AudioSystem_setUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
+ jint userId, jintArray deviceTypes,
+ jobjectArray deviceAddresses) {
+ Vector<AudioDeviceTypeAddr> deviceVector;
+ jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector);
+ if (results != NO_ERROR) {
+ return results;
+ }
+ status_t status = AudioSystem::setUserIdDeviceAffinities((int)userId, deviceVector);
+ return (jint)nativeToJavaStatus(status);
+}
+
+static jint android_media_AudioSystem_removeUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
+ jint userId) {
+ status_t status = AudioSystem::removeUserIdDeviceAffinities((int)userId);
+ return (jint)nativeToJavaStatus(status);
+}
static jint
android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
@@ -2463,7 +2493,9 @@ static const JNINativeMethod gMethods[] = {
{"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
{"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
{"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
- {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes}
+ {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes},
+ {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I", (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
+ {"removeUserIdDeviceAffinities", "(I)I", (void *)android_media_AudioSystem_removeUserIdDeviceAffinities}
};
static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 01b5920755fa..b01083bba643 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -413,6 +413,12 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO
return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled));
}
+static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate) {
+ Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+ ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
+ return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate));
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gSurfaceMethods[] = {
@@ -447,6 +453,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
(void*)nativeAttachAndQueueBufferWithColorSpace},
{"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
+ {"nativeSetFrameRate", "(JF)I", (void*)nativeSetFrameRate},
};
int register_android_view_Surface(JNIEnv* env)
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e0f9571472da..2b9d45431582 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -584,6 +584,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb
transaction->setShadowRadius(ctrl, shadowRadius);
}
+static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
+ jfloat frameRate) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->setFrameRate(ctrl, frameRate);
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1383,6 +1391,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetLayerStack },
{"nativeSetShadowRadius", "(JJF)V",
(void*)nativeSetShadowRadius },
+ {"nativeSetFrameRate", "(JJF)V",
+ (void*)nativeSetFrameRate },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
diff --git a/core/proto/android/hardware/location/context_hub_info.proto b/core/proto/android/hardware/location/context_hub_info.proto
new file mode 100644
index 000000000000..de5cd55fafaf
--- /dev/null
+++ b/core/proto/android/hardware/location/context_hub_info.proto
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.hardware.location;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+message ContextHubInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Context hub unique identifier
+ optional int32 id = 1;
+ // A name for the hub
+ optional string name = 2;
+ // A name for the vendor
+ optional string vendor = 3;
+ // Description of the tool chain
+ optional string toolchain = 4;
+ optional int32 platform_version = 5;
+ optional int32 static_sw_version = 6;
+ optional int32 toolchain_version = 7;
+ // The CHRE platform ID as defined in chre/version.h
+ optional int64 chre_platform_id = 8;
+ // Peak MIPS that this hub can deliver
+ optional float peak_mips = 9;
+ // Power draw in stopped state in milli watts
+ optional float stopped_power_draw_mw = 10;
+ // Power draw in sleep state in milli watts
+ optional float sleep_power_draw_mw = 11;
+ // Peak power draw in milli watts
+ optional float peak_power_draw_mw = 12;
+ // The maximum number of bytes that can be sent per message to the hub
+ optional int32 max_packet_length_bytes = 13;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index d08cbed5909d..8adcc9ed905d 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -36,6 +36,7 @@ import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
import "frameworks/base/core/proto/android/server/fingerprint.proto";
import "frameworks/base/core/proto/android/server/jobscheduler.proto";
+import "frameworks/base/core/proto/android/server/location/context_hub.proto";
import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
import "frameworks/base/core/proto/android/server/rolemanagerservice.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
@@ -486,6 +487,11 @@ message IncidentProto {
(section).args = "connmetrics --proto"
];
+ optional com.android.server.location.ContextHubServiceProto context_hub = 3051 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "contexthub --proto"
+ ];
+
// Reserved for OEMs.
extensions 50000 to 100000;
}
diff --git a/core/proto/android/server/location/context_hub.proto b/core/proto/android/server/location/context_hub.proto
new file mode 100644
index 000000000000..c87f79193ee3
--- /dev/null
+++ b/core/proto/android/server/location/context_hub.proto
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.server.location;
+
+import "frameworks/base/core/proto/android/hardware/location/context_hub_info.proto";
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+message ContextHubServiceProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ repeated .android.hardware.location.ContextHubInfoProto context_hub_info = 1;
+ optional ClientManagerProto client_manager = 2;
+}
+
+message ClientManagerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ message RegistrationRecord {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int64 timestamp_ms = 1;
+ optional int32 action = 2;
+ // ClientBroker endpoint id, contexthub id and package name
+ optional string broker = 3;
+ }
+
+ repeated ClientBrokerProto client_brokers = 1;
+ repeated RegistrationRecord registration_records = 2;
+}
+
+message ClientBrokerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 endpoint_id = 1;
+ optional int32 attached_context_hub_id = 2;
+ optional string package = 3;
+ optional int64 nano_app_id = 4;
+ optional bool pending_intent_request_valid = 5;
+ optional bool has_pending_intent = 6;
+ optional bool pending_intent_cancelled = 7;
+ optional bool registered = 8;
+
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3c657530061b..4595bab82465 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1616,6 +1616,7 @@
<!-- Allows applications to request network
recommendations and scores from the NetworkScoreService.
+ @SystemApi
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
android:protectionLevel="signature|setup" />
@@ -2253,6 +2254,9 @@
<eat-comment />
<!-- @SystemApi @TestApi Allows an application to write to internal media storage
+ @deprecated This permission is no longer honored in the system and no longer adds
+ the media_rw gid as a supplementary gid to the holder. Use the
+ android.permission.MANAGE_EXTERNAL_STORAGE instead.
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
android:protectionLevel="signature|privileged" />
@@ -2531,6 +2535,14 @@
android:description="@string/permdesc_useDataInBackground"
android:protectionLevel="normal" />
+ <!-- Allows a companion app to associate to Wi-Fi.
+ <p>Only for use by a single pre-approved app.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
+ android:protectionLevel="signature|privileged" />
+
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
@@ -2709,6 +2721,11 @@
<permission android:name="android.permission.READ_DEVICE_CONFIG"
android:protectionLevel="signature|preinstalled" />
+ <!-- @SystemApi @hide Allows an application to monitor config settings access.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
+ android:protectionLevel="signature"/>
+
<!-- @SystemApi @TestApi Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
@@ -3715,6 +3732,13 @@
<permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
android:protectionLevel="signature" />
+ <!-- Allows an application to control the lights on the device.
+ @hide
+ @SystemApi
+ @TestApi -->
+ <permission android:name="android.permission.CONTROL_DEVICE_LIGHTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to control the color saturation of the display.
@hide
@SystemApi -->
@@ -3793,6 +3817,24 @@
<permission android:name="android.permission.CAPTURE_MEDIA_OUTPUT"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to capture the audio played by other apps
+ with the {@code USAGE_VOICE_COMMUNICATION} usage.
+
+ The application may opt out of capturing by setting an allow capture policy of
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+
+ There are strong restriction listed at
+ {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}
+ on what an app can do with the captured audio.
+
+ See {@code CAPTURE_AUDIO_OUTPUT} and {@code CAPTURE_MEDIA_OUTPUT} for capturing
+ audio use cases other than voice communication playback.
+
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to capture audio for hotword detection.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/layout/autofill_inline_suggestion.xml b/core/res/res/layout/autofill_inline_suggestion.xml
index f7ac1642f6b7..27faea4b00de 100644
--- a/core/res/res/layout/autofill_inline_suggestion.xml
+++ b/core/res/res/layout/autofill_inline_suggestion.xml
@@ -16,19 +16,20 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
+ style="?android:attr/autofillInlineSuggestionChip"
android:layout_width="wrap_content"
- android:layout_height="56dp"
- android:background="@color/white"
- android:orientation="horizontal"
- android:paddingStart="12dp"
- android:paddingEnd="12dp">
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:orientation="horizontal">
<ImageView
android:id="@+id/autofill_inline_suggestion_start_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center"
+ android:scaleType="fitCenter"
android:contentDescription="autofill_inline_suggestion_start_icon" />
<LinearLayout
@@ -36,32 +37,33 @@
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
- android:layout_marginStart="12dp"
- android:layout_marginEnd="12dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:orientation="vertical"
- android:gravity="center_vertical">
+ android:gravity="center">
<TextView
+ style="?android:attr/autofillInlineSuggestionTitle"
android:id="@+id/autofill_inline_suggestion_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
- android:maxLines="1"
- tools:text="username1"/>
+ android:maxLines="1"/>
<TextView
+ style="?android:attr/autofillInlineSuggestionSubtitle"
android:id="@+id/autofill_inline_suggestion_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
- android:maxLines="1"
- tools:text="inline fill service"/>
+ android:maxLines="1"/>
</LinearLayout>
<ImageView
android:id="@+id/autofill_inline_suggestion_end_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center"
+ android:scaleType="fitCenter"
android:contentDescription="autofill_inline_suggestion_end_icon" />
</LinearLayout>
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 0c45e45e7980..4e8a41f81c48 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -61,10 +61,33 @@
android:layout_height="wrap_content"
android:visibility="gone" />
- <com.android.internal.widget.ViewPager
- android:id="@+id/profile_pager"
+ <TabHost
+ android:id="@+id/profile_tabhost"
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ </TabWidget>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
<TextView android:id="@+id/empty"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index c5d891254227..757cd539152d 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -70,14 +70,44 @@
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <com.android.internal.app.WrapHeightViewPager
- android:id="@+id/profile_pager"
+ <FrameLayout
+ android:id="@+id/stub"
+ android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:divider="?attr/dividerVertical"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"
- android:dividerHeight="1dp"/>
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ </TabWidget>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="?attr/dividerVertical"
+ android:footerDividersEnabled="false"
+ android:headerDividersEnabled="false"
+ android:dividerHeight="1dp"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
<View
android:layout_alwaysShow="true"
diff --git a/core/res/res/layout/resolver_list_per_profile.xml b/core/res/res/layout/resolver_list_per_profile.xml
index 68b991755e73..6d8d3480dc8c 100644
--- a/core/res/res/layout/resolver_list_per_profile.xml
+++ b/core/res/res/layout/resolver_list_per_profile.xml
@@ -25,7 +25,7 @@
android:nestedScrollingEnabled="true"
android:scrollbarStyle="outsideOverlay"
android:scrollIndicators="top|bottom"
- android:divider="?attr/dividerVertical"
+ android:divider="@null"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
- android:dividerHeight="1dp" /> \ No newline at end of file
+ android:dividerHeight="0dp" /> \ No newline at end of file
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 5b3d929d23a5..b54673834ea9 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -151,14 +151,46 @@
android:background="?attr/colorBackgroundFloating"
android:foreground="?attr/dividerVertical" />
- <com.android.internal.app.WrapHeightViewPager
- android:id="@+id/profile_pager"
+ <FrameLayout
+ android:id="@+id/stub"
+ android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:dividerHeight="1dp"
- android:divider="?attr/dividerVertical"
- android:footerDividersEnabled="false"
- android:headerDividersEnabled="false"/>
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:dividerHeight="1dp"
+ android:divider="?attr/dividerVertical"
+ android:footerDividersEnabled="false"
+ android:headerDividersEnabled="false"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
<View
android:layout_alwaysShow="true"
android:layout_width="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 940e9f1ef88b..c9c47b92f782 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9197,4 +9197,12 @@
</declare-styleable>
<attr name="autoSizePresetSizes" />
+
+ <declare-styleable name="AutofillInlineSuggestion">
+ <!-- @hide @SystemApi -->
+ <attr name="isAutofillInlineSuggestionTheme" format="boolean" />
+ <attr name="autofillInlineSuggestionChip" format="reference" />
+ <attr name="autofillInlineSuggestionTitle" format="reference" />
+ <attr name="autofillInlineSuggestionSubtitle" format="reference" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0895edc1da70..cfed805d5d88 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2260,6 +2260,55 @@
<attr name="name" />
</declare-styleable>
+ <!-- The <code>processes</code> tag specifies the processes the application will run code in
+ and optionally characteristics of those processes. This tag is optional; if not
+ specified, components will simply run in the processes they specify. If supplied,
+ they can only specify processes that are enumerated here, and if they don't this
+ will be treated as a corrupt apk and result in an install failure.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestApplication application} tag. -->
+ <declare-styleable name="AndroidManifestProcesses" parent="AndroidManifestApplication">
+ </declare-styleable>
+
+ <!-- The <code>process</code> tag enumerates one of the available processes under its
+ containing <code>processes</code> tag.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} tag. -->
+ <declare-styleable name="AndroidManifestProcess" parent="AndroidManifestProcesses">
+ <!-- Required name of the process that is allowed -->
+ <attr name="process" />
+ </declare-styleable>
+
+ <!-- The <code>deny-permission</code> tag specifies that a permission is to be denied
+ for a particular process (if specified under the
+ {@link #AndroidManifestProcess process} tag) or by default for all
+ processes {if specified under the
+ @link #AndroidManifestProcesses processes} tag).
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} and
+ {@link #AndroidManifestProcess process} tags. -->
+ <declare-styleable name="AndroidManifestDenyPermission"
+ parent="AndroidManifestProcesses">
+ <!-- Required name of the permission that is to be denied -->
+ <attr name="name" />
+ </declare-styleable>
+
+ <!-- The <code>allow-permission</code> tag specifies that a permission is to be allowed
+ for a particular process, when it was previously denied for all processes through
+ {@link #AndroidManifestDenyPermission deny-permission}
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} and
+ {@link #AndroidManifestProcess process} tags. -->
+ <declare-styleable name="AndroidManifestAllowPermission"
+ parent="AndroidManifestProcesses">
+ <!-- Required name of the permission that is to be allowed. -->
+ <attr name="name" />
+ </declare-styleable>
+
<!-- The <code>provider</code> tag declares a
{@link android.content.ContentProvider} class that is available
as part of the package's application components, supplying structured
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 1dcd389d9d8f..731e2ec95f9e 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -224,4 +224,6 @@
<!-- Resolver/Chooser -->
<color name="resolver_text_color_secondary_dark">#ffC4C6C6</color>
+ <color name="resolver_tabs_active_color">#FF1A73E8</color>
+ <color name="resolver_tabs_inactive_color">#FF80868B</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7fd444a1a416..dadb92415839 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1628,29 +1628,21 @@
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
<integer name="config_timeZoneRulesCheckRetryCount">5</integer>
- <!-- Whether to enable network location overlay which allows network
- location provider to be replaced by an app at run-time. When disabled,
- only the config_networkLocationProviderPackageName package will be
- searched for network location provider, otherwise packages whose
- signature matches the signatures of config_locationProviderPackageNames
- will be searched, and the service with the highest version number will
- be picked. Anyone who wants to disable the overlay mechanism can set it
- to false.
- -->
+ <!-- Whether to enable network location overlay which allows network location provider to be
+ replaced by an app at run-time. When disabled, only the
+ config_networkLocationProviderPackageName package will be searched for network location
+ provider, otherwise any system package is eligible. Anyone who wants to disable the overlay
+ mechanism can set it to false. -->
<bool name="config_enableNetworkLocationOverlay" translatable="false">true</bool>
<!-- Package name providing network location support. Used only when
config_enableNetworkLocationOverlay is false. -->
<string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
- <!-- Whether to enable fused location provider overlay which allows fused
- location provider to be replaced by an app at run-time. When disabled,
- only the config_fusedLocationProviderPackageName package will be
- searched for fused location provider, otherwise packages whose
- signature matches the signatures of config_locationProviderPackageNames
- will be searched, and the service with the highest version number will
- be picked. Anyone who wants to disable the overlay mechanism can set it
- to false.
- -->
+ <!-- Whether to enable fused location provider overlay which allows fused location provider to
+ be replaced by an app at run-time. When disabled, only the
+ config_fusedLocationProviderPackageName package will be searched for fused location
+ provider, otherwise any system package is eligible. Anyone who wants to disable the overlay
+ mechanism can set it to false. -->
<bool name="config_enableFusedLocationOverlay" translatable="false">true</bool>
<!-- Package name providing fused location support. Used only when
config_enableFusedLocationOverlay is false. -->
@@ -1669,25 +1661,10 @@
-->
<string name="config_defaultNetworkRecommendationProviderPackage" translatable="false"></string>
- <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
- replaced by an app at run-time. When disabled, only the
- config_hardwareFlpPackageName package will be searched for Hardware Flp,
- otherwise packages whose signature matches the signatures of
- config_locationProviderPackageNames will be searched, and the service
- with the highest version number will be picked. Anyone who wants to
- disable the overlay mechanism can set it to false.
- -->
- <bool name="config_enableHardwareFlpOverlay" translatable="false">true</bool>
- <!-- Package name providing Hardware Flp. Used only when
- config_enableHardwareFlpOverlay is false. -->
- <string name="config_hardwareFlpPackageName" translatable="false">com.android.location.fused</string>
-
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
config_geocoderProviderPackageName package will be searched for
- geocoder, otherwise packages whose signature matches the signatures of
- config_locationProviderPackageNames will be searched, and the service
- with the highest version number will be picked. Anyone who wants to
+ geocoder, otherwise any system package is eligible. Anyone who wants to
disable the overlay mechanism can set it to false.
-->
<bool name="config_enableGeocoderOverlay" translatable="false">true</bool>
@@ -1698,9 +1675,7 @@
<!-- Whether to enable geofence overlay which allows geofence to be replaced
by an app at run-time. When disabled, only the
config_geofenceProviderPackageName package will be searched for
- geofence implementation, otherwise packages whose signature matches the
- signatures of config_locationProviderPackageNames will be searched, and
- the service with the highest version number will be picked. Anyone who
+ geofence implementation, otherwise any system package is eligible. Anyone who
wants to disable the overlay mechanism can set it to false.
-->
<bool name="config_enableGeofenceOverlay" translatable="false">true</bool>
@@ -1711,9 +1686,7 @@
<!-- Whether to enable Hardware Activity-Recognition overlay which allows Hardware
Activity-Recognition to be replaced by an app at run-time. When disabled, only the
config_activityRecognitionHardwarePackageName package will be searched for
- its implementation, otherwise packages whose signature matches the
- signatures of config_locationProviderPackageNames will be searched, and
- the service with the highest version number will be picked. Anyone who
+ its implementation, otherwise any system package is eligible. Anyone who
wants to disable the overlay mechanism can set it to false.
-->
<bool name="config_enableActivityRecognitionHardwareOverlay" translatable="false">true</bool>
@@ -1721,19 +1694,8 @@
config_enableActivityRecognitionHardwareOverlay is false. -->
<string name="config_activityRecognitionHardwarePackageName" translatable="false">@null</string>
- <!-- Package name(s) containing location provider support.
- These packages can contain services implementing location providers,
- such as the Geocode Provider, Network Location Provider, and
- Fused Location Provider. They will each be searched for
- service components implementing these providers.
- It is strongly recommended that the packages explicitly named
- below are on the system image, so that they will not map to
- a 3rd party application.
- The location framework also has support for installation
- of new location providers at run-time. The new package does not
- have to be explicitly listed here, however it must have a signature
- that matches the signature of at least one package on this list.
- -->
+ <!-- Package name(s) containing location provider support. These packages will be auto-granted
+ several permissions by the system, and should be system packages. -->
<string-array name="config_locationProviderPackageNames" translatable="false">
<!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item>
@@ -2723,6 +2685,11 @@
<!-- The amount to scale fullscreen snapshots for Overview and snapshot starting windows. -->
<item name="config_fullTaskSnapshotScale" format="float" type="dimen">1.0</item>
+ <!-- The amount to scale reduced scale snapshots for Overview and snapshot starting windows.
+ Reduced scale snapshots are loaded before full screen snapshots to improve load times and
+ minimize the chance the user will see an empty task card. -->
+ <item name="config_reducedTaskSnapshotScale" format="float" type="dimen">0.5</item>
+
<!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->
<bool name="config_use16BitTaskSnapshotPixelFormat">false</bool>
@@ -4211,7 +4178,7 @@
where: IDs are unique per device, Modality as defined in BiometricAuthenticator.java,
and Strength as defined in Authenticators.java -->
<string-array name="config_biometric_sensors" translatable="false" >
- <item>0:2:15</item> <!-- ID0:Fingerprint:Strong -->
+ <!-- <item>0:2:15</item> ID0:Fingerprint:Strong -->
</string-array>
<!-- Messages that should not be shown to the user during face auth enrollment. This should be
@@ -4326,6 +4293,13 @@
generation). -->
<bool name="config_customBugreport">false</bool>
+ <!-- Names of packages that should not be suspended when personal use is blocked by policy. -->
+ <string-array name="config_packagesExemptFromSuspension" translatable="false">
+ <!-- Add packages here, example: -->
+ <!-- <item>com.android.settings</item> -->
+ </string-array>
+
+
<!-- Class name of the custom country detector to be used. -->
<string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5d8d31debb54..4f61730ad2e2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3012,12 +3012,18 @@
<public name="sdkVersion" />
<!-- @hide @SystemApi -->
<public name="minExtensionVersion" />
+ <public name="autofillInlineSuggestionChip" />
+ <public name="autofillInlineSuggestionTitle" />
+ <public name="autofillInlineSuggestionSubtitle" />
+ <!-- @hide @SystemApi -->
+ <public name="isAutofillInlineSuggestionTheme" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
</public-group>
<public-group type="style" first-id="0x010302e5">
+ <public name="Theme.AutofillInlineSuggestion" />
</public-group>
<public-group type="id" first-id="0x0102004a">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bed418dc4c2d..be2b678565d3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -425,6 +425,12 @@
<!-- A toast message displayed when printing is attempted but disabled by policy. -->
<string name="printing_disabled_by">Printing disabled by <xliff:g id="owner_app">%s</xliff:g>.</string>
+ <!-- Content title for a notification that personal apps are suspended [CHAR LIMIT=NONE] -->
+ <string name="personal_apps_suspended_notification_title">Personal apps have been suspended by an admin</string>
+
+ <!-- Message for a notification about personal apps suspension when work profile is off. [CHAR LIMIT=NONE] -->
+ <string name="personal_apps_suspended_notification_text">Tap here to check policy compliance.</string>
+
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
@@ -5319,4 +5325,8 @@
<!-- Text to tell the user that a package has been forced by themselves in the RESTRICTED bucket. [CHAR LIMIT=NONE] -->
<string name="as_app_forced_to_restricted_bucket">
<xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string>
+
+ <!-- ResolverActivity - profile tabs -->
+ <string name="resolver_personal_tab">Personal</string>
+ <string name="resolver_work_tab">Work</string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index bcce1f05f0dd..751eca036ba6 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1482,6 +1482,22 @@ please see styles_device_defaults.xml.
<item name="android:windowExitAnimation">@anim/slide_out_down</item>
</style>
+ <!-- The style for the Autofill inline suggestion chip. -->
+ <!-- @hide -->
+ <style name="AutofillInlineSuggestionChip">
+ <item name="background">@drawable/autofill_dataset_picker_background</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="AutofillInlineSuggestionTitle">
+ <item name="android:textAppearance">@style/TextAppearance</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="AutofillInlineSuggestionSubtitle">
+ <item name="android:textAppearance">@style/TextAppearance.Small</item>
+ </style>
+
<!-- The style for the container of media actions in a notification. -->
<!-- @hide -->
<style name="NotificationMediaActionContainer">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 703281964442..18ca003dd8c6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -249,6 +249,9 @@
<java-symbol type="id" name="app_ops" />
<java-symbol type="id" name="profile_pager" />
<java-symbol type="id" name="content_preview_container" />
+ <java-symbol type="id" name="profile_tabhost" />
+ <java-symbol type="id" name="tabs" />
+ <java-symbol type="id" name="tabcontent" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -357,6 +360,7 @@
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
<java-symbol type="dimen" name="config_fullTaskSnapshotScale" />
+ <java-symbol type="dimen" name="config_reducedTaskSnapshotScale" />
<java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="string" name="config_recentsComponentName" />
@@ -1209,6 +1213,8 @@
<java-symbol type="string" name="device_ownership_relinquished" />
<java-symbol type="string" name="network_logging_notification_title" />
<java-symbol type="string" name="network_logging_notification_text" />
+ <java-symbol type="string" name="personal_apps_suspended_notification_title" />
+ <java-symbol type="string" name="personal_apps_suspended_notification_text" />
<java-symbol type="string" name="factory_reset_warning" />
<java-symbol type="string" name="factory_reset_message" />
<java-symbol type="string" name="lockscreen_transport_play_description" />
@@ -1869,7 +1875,6 @@
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
- <java-symbol type="bool" name="config_enableHardwareFlpOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
<java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
@@ -2019,7 +2024,6 @@
<java-symbol type="string" name="config_datause_iface" />
<java-symbol type="string" name="config_activityRecognitionHardwarePackageName" />
<java-symbol type="string" name="config_fusedLocationProviderPackageName" />
- <java-symbol type="string" name="config_hardwareFlpPackageName" />
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
@@ -3822,6 +3826,9 @@
<java-symbol type="dimen" name="waterfall_display_right_edge_size" />
<java-symbol type="dimen" name="waterfall_display_bottom_edge_size" />
+ <!-- For device policy -->
+ <java-symbol type="array" name="config_packagesExemptFromSuspension" />
+
<!-- Accessibility take screenshot -->
<java-symbol type="string" name="capability_desc_canTakeScreenshot" />
<java-symbol type="string" name="capability_title_canTakeScreenshot" />
@@ -3833,4 +3840,12 @@
<java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" />
<java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" />
+
+ <!-- Intent resolver and share sheet -->
+ <java-symbol type="color" name="resolver_tabs_active_color" />
+ <java-symbol type="color" name="resolver_tabs_inactive_color" />
+ <java-symbol type="string" name="resolver_personal_tab" />
+ <java-symbol type="string" name="resolver_work_tab" />
+ <java-symbol type="id" name="stub" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index ad38f3d57c23..5e6dd8294776 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -893,4 +893,11 @@ please see themes_device_defaults.xml.
<item name="windowActivityTransitions">false</item>
</style>
+ <!-- Theme for the Autofill inline suggestion on IME -->
+ <style name="Theme.AutofillInlineSuggestion" parent="Theme.DeviceDefault">
+ <item name="isAutofillInlineSuggestionTheme">true</item>
+ <item name="autofillInlineSuggestionChip">@style/AutofillInlineSuggestionChip</item>
+ <item name="autofillInlineSuggestionTitle">@style/AutofillInlineSuggestionTitle</item>
+ <item name="autofillInlineSuggestionSubtitle">@style/AutofillInlineSuggestionSubtitle</item>
+ </style>
</resources>
diff --git a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java b/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
new file mode 100644
index 000000000000..3103708f985d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/SnippetTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SnippetMatchProto;
+import com.google.android.icing.proto.SnippetProto;
+
+import org.junit.Test;
+
+@SmallTest
+public class SnippetTest {
+
+ // TODO(sidchhabra): Add tests for Double and Long Snippets.
+ @Test
+ public void testSingleStringSnippet() {
+
+ final String propertyKeyString = "content";
+ final String propertyValueString = "A commonly used fake word is foo.\n"
+ + " Another nonsense word that’s used a lot\n"
+ + " is bar.\n";
+ final String uri = "uri1";
+ final String schemaType = "schema1";
+ final String searchWord = "foo";
+ final String exactMatch = "foo";
+ final String window = "is foo";
+
+ // Building the SearchResult received from query.
+ PropertyProto property = PropertyProto.newBuilder()
+ .setName(propertyKeyString)
+ .addStringValues(propertyValueString)
+ .build();
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri(uri)
+ .setSchema(schemaType)
+ .addProperties(property)
+ .build();
+ SnippetProto snippetProto = SnippetProto.newBuilder()
+ .addEntries(SnippetProto.EntryProto.newBuilder()
+ .setPropertyName(propertyKeyString)
+ .addSnippetMatches(SnippetMatchProto.newBuilder()
+ .setValuesIndex(0)
+ .setExactMatchPosition(29)
+ .setExactMatchBytes(3)
+ .setWindowPosition(26)
+ .setWindowBytes(6)
+ .build())
+ .build())
+ .build();
+ SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .setSnippet(snippetProto)
+ .build();
+ SearchResultProto searchResultProto = SearchResultProto.newBuilder()
+ .addResults(resultProto)
+ .build();
+ SearchResults searchResults = new SearchResults(searchResultProto);
+
+ // Making ResultReader and getting Snippet values.
+ while (searchResults.hasNext()) {
+ SearchResults.Result result = searchResults.next();
+ MatchInfo match = result.getMatchInfo().get(0);
+ assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
+ assertThat(match.getFullText()).isEqualTo(propertyValueString);
+ assertThat(match.getExactMatch()).isEqualTo(exactMatch);
+ assertThat(match.getSnippet()).isEqualTo(window);
+ }
+ }
+
+ // TODO(sidchhabra): Add tests for Double and Long Snippets.
+ @Test
+ public void testNoSnippets() {
+
+ final String propertyKeyString = "content";
+ final String propertyValueString = "A commonly used fake word is foo.\n"
+ + " Another nonsense word that’s used a lot\n"
+ + " is bar.\n";
+ final String uri = "uri1";
+ final String schemaType = "schema1";
+ final String searchWord = "foo";
+ final String exactMatch = "foo";
+ final String window = "is foo";
+
+ // Building the SearchResult received from query.
+ PropertyProto property = PropertyProto.newBuilder()
+ .setName(propertyKeyString)
+ .addStringValues(propertyValueString)
+ .build();
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri(uri)
+ .setSchema(schemaType)
+ .addProperties(property)
+ .build();
+ SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .build();
+ SearchResultProto searchResultProto = SearchResultProto.newBuilder()
+ .addResults(resultProto)
+ .build();
+ SearchResults searchResults = new SearchResults(searchResultProto);
+
+ while (searchResults.hasNext()) {
+ SearchResults.Result result = searchResults.next();
+ assertThat(result.getMatchInfo()).isEqualTo(null);
+ }
+ }
+
+ @Test
+ public void testMultipleStringSnippet() {
+ final String searchWord = "Test";
+
+ // Building the SearchResult received from query.
+ PropertyProto property1 = PropertyProto.newBuilder()
+ .setName("sender.name")
+ .addStringValues("Test Name Jr.")
+ .build();
+ PropertyProto property2 = PropertyProto.newBuilder()
+ .setName("sender.email")
+ .addStringValues("TestNameJr@gmail.com")
+ .build();
+ DocumentProto documentProto = DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema("schema1")
+ .addProperties(property1)
+ .addProperties(property2)
+ .build();
+ SnippetProto snippetProto = SnippetProto.newBuilder()
+ .addEntries(
+ SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("sender.name")
+ .addSnippetMatches(
+ SnippetMatchProto.newBuilder()
+ .setValuesIndex(0)
+ .setExactMatchPosition(0)
+ .setExactMatchBytes(4)
+ .setWindowPosition(0)
+ .setWindowBytes(9)
+ .build())
+ .build())
+ .addEntries(
+ SnippetProto.EntryProto.newBuilder()
+ .setPropertyName("sender.email")
+ .addSnippetMatches(
+ SnippetMatchProto.newBuilder()
+ .setValuesIndex(0)
+ .setExactMatchPosition(0)
+ .setExactMatchBytes(20)
+ .setWindowPosition(0)
+ .setWindowBytes(20)
+ .build())
+ .build()
+ )
+ .build();
+ SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder()
+ .setDocument(documentProto)
+ .setSnippet(snippetProto)
+ .build();
+ SearchResultProto searchResultProto = SearchResultProto.newBuilder()
+ .addResults(resultProto)
+ .build();
+ SearchResults searchResults = new SearchResults(searchResultProto);
+
+ // Making ResultReader and getting Snippet values.
+ while (searchResults.hasNext()) {
+ SearchResults.Result result = searchResults.next();
+
+ MatchInfo match1 = result.getMatchInfo().get(0);
+ assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
+ assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
+ assertThat(match1.getExactMatch()).isEqualTo("Test");
+ assertThat(match1.getSnippet()).isEqualTo("Test Name");
+
+ MatchInfo match2 = result.getMatchInfo().get(1);
+ assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
+ assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
+ assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com");
+ assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com");
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index f2852fa49b5e..bcf0b8ce4439 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -41,6 +41,7 @@ import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.animation.LinearInterpolator;
import android.view.test.InsetsModeSession;
import androidx.test.runner.AndroidJUnit4;
@@ -121,7 +122,7 @@ public class InsetsAnimationControlImplTest {
controls.put(ITYPE_NAVIGATION_BAR, navConsumer.getControl());
mController = new InsetsAnimationControlImpl(controls,
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
- mMockController, 10 /* durationMs */,
+ mMockController, 10 /* durationMs */, new LinearInterpolator(),
false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN);
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 838190387c35..f720c987a525 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -44,6 +44,7 @@ import android.platform.test.annotations.Presubmit;
import android.view.WindowInsets.Type;
import android.view.WindowManager.BadTokenException;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.LinearInterpolator;
import android.view.test.InsetsModeSession;
import android.widget.TextView;
@@ -148,7 +149,7 @@ public class InsetsControllerTest {
WindowInsetsAnimationControlListener mockListener =
mock(WindowInsetsAnimationControlListener.class);
mController.controlWindowInsetsAnimation(statusBars(), 10 /* durationMs */,
- mockListener);
+ new LinearInterpolator(), mockListener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -164,7 +165,8 @@ public class InsetsControllerTest {
mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
WindowInsetsAnimationControlListener controlListener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, controlListener);
+ mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(),
+ controlListener);
verify(controlListener).onCancelled();
verify(controlListener, never()).onReady(any(), anyInt());
}
@@ -375,7 +377,7 @@ public class InsetsControllerTest {
WindowInsetsAnimationControlListener mockListener =
mock(WindowInsetsAnimationControlListener.class);
mController.controlWindowInsetsAnimation(statusBars(), 0 /* durationMs */,
- mockListener);
+ new LinearInterpolator(), mockListener);
ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 9e4b1c55304f..20be8c22ccfc 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -94,7 +94,7 @@ public class InsetsStateTest {
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, 0, null);
assertEquals(100, insets.getStableInsetBottom());
- assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.systemBars()));
+ assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(Type.systemBars()));
assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all()));
assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.navigationBars()));
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index cf5d079ba688..df6ed8c3fe0d 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -109,7 +109,7 @@ public class ViewRootImplTest {
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.statusBars());
+ assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars());
}
@Test
@@ -120,7 +120,7 @@ public class ViewRootImplTest {
attrs.flags = FLAG_LAYOUT_IN_SCREEN;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.statusBars());
+ assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars());
}
@Test
@@ -131,7 +131,7 @@ public class ViewRootImplTest {
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(0, attrs.getFitWindowInsetsTypes() & Type.systemBars());
+ assertEquals(0, attrs.getFitInsetsTypes() & Type.systemBars());
}
@Test
@@ -141,8 +141,8 @@ public class ViewRootImplTest {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_TOAST);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(Type.systemBars(), attrs.getFitWindowInsetsTypes() & Type.systemBars());
- assertEquals(true, attrs.getFitIgnoreVisibility());
+ assertEquals(Type.systemBars(), attrs.getFitInsetsTypes() & Type.systemBars());
+ assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
}
@Test
@@ -152,8 +152,8 @@ public class ViewRootImplTest {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_SYSTEM_ALERT);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(Type.systemBars(), attrs.getFitWindowInsetsTypes() & Type.systemBars());
- assertEquals(true, attrs.getFitIgnoreVisibility());
+ assertEquals(Type.systemBars(), attrs.getFitInsetsTypes() & Type.systemBars());
+ assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
}
@Test
@@ -165,14 +165,14 @@ public class ViewRootImplTest {
final int sides = Side.TOP | Side.LEFT;
final boolean fitMaxInsets = true;
attrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- attrs.setFitWindowInsetsTypes(types);
- attrs.setFitWindowInsetsSides(sides);
- attrs.setFitIgnoreVisibility(fitMaxInsets);
+ attrs.setFitInsetsTypes(types);
+ attrs.setFitInsetsSides(sides);
+ attrs.setFitInsetsIgnoringVisibility(fitMaxInsets);
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
- assertEquals(types, attrs.getFitWindowInsetsTypes());
- assertEquals(sides, attrs.getFitWindowInsetsSides());
- assertEquals(fitMaxInsets, attrs.getFitIgnoreVisibility());
+ assertEquals(types, attrs.getFitInsetsTypes());
+ assertEquals(sides, attrs.getFitInsetsSides());
+ assertEquals(fitMaxInsets, attrs.isFitInsetsIgnoringVisibility());
}
private static class ViewRootImplAccessor {
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
index 68099fe19d13..12c057f5a91a 100644
--- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -18,9 +18,15 @@ package android.view.inputmethod;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.UserHandle;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -71,4 +77,227 @@ public class EditorInfoTest {
}
}
}
+
+ @Test
+ public void testNullTextInputComposeInitialSurroundingText() {
+ final Spannable testText = null;
+ final EditorInfo editorInfo = new EditorInfo();
+
+ try {
+ editorInfo.setInitialSurroundingText(testText);
+ fail("Shall not take null input");
+ } catch (NullPointerException expected) {
+ // Expected behavior, nothing to do.
+ }
+ }
+
+ @Test
+ public void testNonNullTextInputComposeInitialSurroundingText() {
+ final Spannable testText = createTestText(/* prependLength= */ 0,
+ EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH);
+ final EditorInfo editorInfo = new EditorInfo();
+
+ // Cursor at position 0.
+ int selectionLength = 0;
+ editorInfo.initialSelStart = 0;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
+ int expectedTextBeforeCursorLength = 0;
+ int expectedTextAfterCursorLength = testText.length();
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Cursor at the end.
+ editorInfo.initialSelStart = testText.length() - selectionLength;
+ editorInfo.initialSelEnd = testText.length();
+ expectedTextBeforeCursorLength = testText.length();
+ expectedTextAfterCursorLength = 0;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Cursor at the middle.
+ selectionLength = 2;
+ editorInfo.initialSelStart = testText.length() / 2;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
+ expectedTextBeforeCursorLength = editorInfo.initialSelStart;
+ expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Accidentally swap selection start and end.
+ editorInfo.initialSelEnd = testText.length() / 2;
+ editorInfo.initialSelStart = editorInfo.initialSelEnd + selectionLength;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Invalid cursor position.
+ editorInfo.initialSelStart = -1;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo,
+ /* expectBeforeCursorLength= */null,
+ /* expectSelectionLength= */null,
+ /* expectAfterCursorLength= */null);
+ }
+
+ @Test
+ public void testTooLongTextInputComposeInitialSurroundingText() {
+ final Spannable testText = createTestText(/* prependLength= */ 0,
+ EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH + 2);
+ final EditorInfo editorInfo = new EditorInfo();
+
+ // Cursor at position 0.
+ int selectionLength = 0;
+ editorInfo.initialSelStart = 0;
+ editorInfo.initialSelEnd = 0 + selectionLength;
+ int expectedTextBeforeCursorLength = 0;
+ int expectedTextAfterCursorLength = editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Cursor at the end.
+ editorInfo.initialSelStart = testText.length() - selectionLength;
+ editorInfo.initialSelEnd = testText.length();
+ expectedTextBeforeCursorLength = editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
+ expectedTextAfterCursorLength = 0;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Cursor at the middle.
+ selectionLength = 2;
+ editorInfo.initialSelStart = testText.length() / 2;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
+ expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
+ (int) (0.8 * (EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH - selectionLength)));
+ expectedTextAfterCursorLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH
+ - expectedTextBeforeCursorLength - selectionLength;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Accidentally swap selection start and end.
+ editorInfo.initialSelEnd = testText.length() / 2;
+ editorInfo.initialSelStart = editorInfo.initialSelEnd + selectionLength;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
+ expectedTextAfterCursorLength);
+
+ // Selection too long, selected text should be dropped.
+ selectionLength = EditorInfo.MAX_INITIAL_SELECTION_LENGTH + 1;
+ editorInfo.initialSelStart = testText.length() / 2;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
+ expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
+ (int) (0.8 * EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH));
+ expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+
+ editorInfo.setInitialSurroundingText(testText);
+
+ assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength,
+ /* expectSelectionLength= */null, expectedTextAfterCursorLength);
+ }
+
+ @Test
+ public void testTooLongSubTextInputComposeInitialSurroundingText() {
+ final int prependLength = 5;
+ final int subTextLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH;
+ final Spannable fullText = createTestText(prependLength, subTextLength);
+ final EditorInfo editorInfo = new EditorInfo();
+ // Cursor at the middle.
+ final int selectionLength = 2;
+ editorInfo.initialSelStart = fullText.length() / 2;
+ editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
+ // #prependLength characters will be trimmed out.
+ final Spannable expectedTextBeforeCursor = createExpectedText(/* startNumber= */0,
+ editorInfo.initialSelStart - prependLength);
+ final Spannable expectedSelectedText = createExpectedText(
+ editorInfo.initialSelStart - prependLength, selectionLength);
+ final Spannable expectedTextAfterCursor = createExpectedText(
+ editorInfo.initialSelEnd - prependLength,
+ fullText.length() - editorInfo.initialSelEnd);
+
+ editorInfo.setInitialSurroundingSubText(fullText.subSequence(prependLength,
+ fullText.length()), prependLength);
+
+ assertTrue(TextUtils.equals(expectedTextBeforeCursor,
+ editorInfo.getInitialTextBeforeCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES)));
+ assertTrue(TextUtils.equals(expectedSelectedText,
+ editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES)));
+ assertTrue(TextUtils.equals(expectedTextAfterCursor,
+ editorInfo.getInitialTextAfterCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES)));
+ }
+
+ private static void assertExpectedTextLength(EditorInfo editorInfo,
+ @Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength,
+ @Nullable Integer expectAfterCursorLength) {
+ final CharSequence textBeforeCursor =
+ editorInfo.getInitialTextBeforeCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES);
+ final CharSequence selectedText =
+ editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
+ final CharSequence textAfterCursor =
+ editorInfo.getInitialTextAfterCursor(editorInfo.MEMORY_EFFICIENT_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES);
+
+ if (expectBeforeCursorLength == null) {
+ assertNull(textBeforeCursor);
+ } else {
+ assertEquals(expectBeforeCursorLength.intValue(), textBeforeCursor.length());
+ }
+
+ if (expectSelectionLength == null) {
+ assertNull(selectedText);
+ } else {
+ assertEquals(expectSelectionLength.intValue(), selectedText.length());
+ }
+
+ if (expectAfterCursorLength == null) {
+ assertNull(textAfterCursor);
+ } else {
+ assertEquals(expectAfterCursorLength.intValue(), textAfterCursor.length());
+ }
+ }
+
+ private static Spannable createTestText(int prependLength, int surroundingLength) {
+ final SpannableStringBuilder builder = new SpannableStringBuilder();
+ for (int i = 0; i < prependLength; i++) {
+ builder.append("a");
+ }
+
+ for (int i = 0; i < surroundingLength; i++) {
+ builder.append(Integer.toString(i % 10));
+ }
+ return builder;
+ }
+
+ private static Spannable createExpectedText(int startNumber, int length) {
+ final SpannableStringBuilder builder = new SpannableStringBuilder();
+ for (int i = startNumber; i < startNumber + length; i++) {
+ builder.append(Integer.toString(i % 10));
+ }
+ return builder;
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index c086421501b5..411868d8befe 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -31,6 +31,7 @@ import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FRO
import static com.android.internal.app.ChooserListAdapter.CALLER_TARGET_SCORE_BOOST;
import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST;
import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
+import static com.android.internal.app.MatcherUtils.first;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
@@ -63,6 +64,8 @@ import android.graphics.Paint;
import android.graphics.drawable.Icon;
import android.metrics.LogMaker;
import android.net.Uri;
+import android.os.Bundle;
+import android.os.UserHandle;
import android.service.chooser.ChooserTarget;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -74,7 +77,11 @@ import com.android.internal.app.chooser.DisplayResolveInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -302,6 +309,7 @@ public class ChooserActivityTest {
assertThat(activity.getIsSelected(), is(true));
}
+ @Ignore // b/148158199
@Test
public void noResultsFromPackageManager() {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
@@ -346,6 +354,9 @@ public class ChooserActivityTest {
@Test
public void hasOtherProfileOneOption() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -372,9 +383,7 @@ public class ChooserActivityTest {
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
+ waitForIdle();
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
waitForIdle();
@@ -383,6 +392,9 @@ public class ChooserActivityTest {
@Test
public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3);
@@ -411,9 +423,6 @@ public class ChooserActivityTest {
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(3);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
waitForIdle();
@@ -422,6 +431,9 @@ public class ChooserActivityTest {
@Test
public void hasLastChosenActivityAndOtherProfile() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3);
@@ -448,9 +460,6 @@ public class ChooserActivityTest {
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(3);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
waitForIdle();
@@ -1161,6 +1170,123 @@ public class ChooserActivityTest {
.getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
}
+ @Test
+ public void testWorkTab_displayedWhenWorkProfileUserAvailable() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+ markWorkProfileUserAvailable();
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+
+ onView(withId(R.id.tabs)).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+
+ onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testWorkTab_eachTabUsesExpectedAdapter() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ int personalProfileTargets = 3;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(personalProfileTargets);
+ int workProfileTargets = 4;
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(
+ workProfileTargets);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+ markWorkProfileUserAvailable();
+
+ final ChooserWrapperActivity activity =
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+
+ assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
+ // The work list adapter must only be filled when we open the work tab
+ assertThat(activity.getWorkListAdapter().getCount(), is(0));
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
+ assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
+ assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
+ }
+
+ @Test
+ public void testWorkTab_workProfileHasExpectedNumberOfTargets() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ int workProfileTargets = 4;
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(workProfileTargets);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ final ChooserWrapperActivity activity =
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
+ }
+
+ @Ignore // b/148156663
+ @Test
+ public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ int workProfileTargets = 4;
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(workProfileTargets);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+ ResolveInfo[] chosen = new ResolveInfo[1];
+ sOverrides.onSafelyStartCallback = targetInfo -> {
+ chosen[0] = targetInfo.getResolveInfo();
+ return true;
+ };
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+ // wait for the share sheet to expand
+ Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+
+ onView(first(withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name)))
+ .perform(click());
+ waitForIdle();
+ assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
+ }
+
private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -1224,6 +1350,15 @@ public class ChooserActivityTest {
return infoList;
}
+ private List<ResolvedComponentInfo> createResolvedComponentsForTestWithUserId(
+ int numberOfResults, int userId) {
+ List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+ for (int i = 0; i < numberOfResults; i++) {
+ infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+ }
+ return infoList;
+ }
+
private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
Icon icon = Icon.createWithBitmap(createBitmap());
String testTitle = "testTitle";
@@ -1308,4 +1443,8 @@ public class ChooserActivityTest {
assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString());
}
}
+
+ private void markWorkProfileUserAvailable() {
+ sOverrides.workProfileUserHandle = UserHandle.of(10);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 2a1044361d42..eee62bb791bf 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -17,6 +17,7 @@
package com.android.internal.app;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.annotation.Nullable;
import android.app.usage.UsageStatsManager;
@@ -29,6 +30,7 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
import android.util.Size;
@@ -51,6 +53,19 @@ public class ChooserWrapperActivity extends ChooserActivity {
return mChooserMultiProfilePagerAdapter.getActiveListAdapter();
}
+ ChooserListAdapter getPersonalListAdapter() {
+ return ((ChooserGridAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(0))
+ .getListAdapter();
+ }
+
+ ChooserListAdapter getWorkListAdapter() {
+ if (mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
+ return null;
+ }
+ return ((ChooserGridAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(1))
+ .getListAdapter();
+ }
+
boolean getIsSelected() { return mIsSuccessfullySelected; }
UsageStatsManager getUsageStatsManager() {
@@ -79,7 +94,12 @@ public class ChooserWrapperActivity extends ChooserActivity {
@Override
protected ResolverListController createListController(UserHandle userHandle) {
- return sOverrides.resolverListController;
+ if (userHandle == UserHandle.SYSTEM) {
+ when(sOverrides.resolverListController.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+ return sOverrides.resolverListController;
+ }
+ when(sOverrides.workResolverListController.getUserHandle()).thenReturn(userHandle);
+ return sOverrides.workResolverListController;
}
@Override
@@ -144,6 +164,15 @@ public class ChooserWrapperActivity extends ChooserActivity {
resolveInfoPresentationGetter);
}
+ @Override
+ protected UserHandle getWorkProfileUserHandle() {
+ return sOverrides.workProfileUserHandle;
+ }
+
+ protected UserHandle getCurrentUserHandle() {
+ return mMultiProfilePagerAdapter.getCurrentUserHandle();
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -154,6 +183,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public ResolverListController resolverListController;
+ public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
public boolean isImageType;
public Cursor resolverCursor;
@@ -162,6 +192,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
public MetricsLogger metricsLogger;
public int alternateProfileSetting;
public Resources resources;
+ public UserHandle workProfileUserHandle;
public void reset() {
onSafelyStartCallback = null;
@@ -172,9 +203,11 @@ public class ChooserWrapperActivity extends ChooserActivity {
resolverCursor = null;
resolverForceException = false;
resolverListController = mock(ResolverListController.class);
+ workResolverListController = mock(ResolverListController.class);
metricsLogger = mock(MetricsLogger.class);
alternateProfileSetting = 0;
resources = null;
+ workProfileUserHandle = null;
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/app/MatcherUtils.java b/core/tests/coretests/src/com/android/internal/app/MatcherUtils.java
new file mode 100644
index 000000000000..a4766318a21e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/MatcherUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+/**
+ * Utils for helping with more customized matching options, for example matching the first
+ * occurrence of a set criteria.
+ */
+public class MatcherUtils {
+
+ /**
+ * Returns a {@link Matcher} which only matches the first occurrence of a set criteria.
+ */
+ static <T> Matcher<T> first(final Matcher<T> matcher) {
+ return new BaseMatcher<T>() {
+ boolean isFirstMatch = true;
+
+ @Override
+ public boolean matches(final Object item) {
+ if (isFirstMatch && matcher.matches(item)) {
+ isFirstMatch = false;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText("Returns the first matching item");
+ }
+ };
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 923ce3e3935d..42f7736d37b0 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -19,13 +19,17 @@ package com.android.internal.app;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static com.android.internal.app.MatcherUtils.first;
import static com.android.internal.app.ResolverDataProvider.createPackageManagerMockedInfo;
import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -33,6 +37,7 @@ import static org.mockito.Mockito.when;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.view.View;
import android.widget.RelativeLayout;
@@ -49,6 +54,9 @@ import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGett
import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
import com.android.internal.widget.ResolverDrawerLayout;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -212,6 +220,9 @@ public class ResolverActivityTest {
@Test
public void hasOtherProfileOneOption() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(2);
@@ -237,9 +248,6 @@ public class ResolverActivityTest {
// Make a stable copy of the components as the original list may be modified
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
onView(withId(R.id.button_once))
@@ -250,6 +258,9 @@ public class ResolverActivityTest {
@Test
public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
Intent sendIntent = createSendImageIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3);
@@ -279,9 +290,6 @@ public class ResolverActivityTest {
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
onView(withId(R.id.button_once)).perform(click());
@@ -292,6 +300,9 @@ public class ResolverActivityTest {
@Test
public void hasLastChosenActivityAndOtherProfile() throws Exception {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+
// In this case we prefer the other profile and don't display anything about the last
// chosen activity.
Intent sendIntent = createSendImageIntent();
@@ -325,9 +336,6 @@ public class ResolverActivityTest {
List<ResolvedComponentInfo> stableCopy =
createResolvedComponentsForTestWithOtherProfile(2);
- // Check that the "Other Profile" activity is put in the right spot
- onView(withId(R.id.profile_button)).check(matches(
- withText(stableCopy.get(0).getResolveInfoAt(0).activityInfo.name)));
onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))
.perform(click());
onView(withId(R.id.button_once)).perform(click());
@@ -379,6 +387,222 @@ public class ResolverActivityTest {
TextUtils.isEmpty(pg.getSubLabel()));
}
+ @Test
+ public void testWorkTab_displayedWhenWorkProfileUserAvailable() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ Intent sendIntent = createSendImageIntent();
+ markWorkProfileUserAvailable();
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ onView(withId(R.id.tabs)).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ Intent sendIntent = createSendImageIntent();
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testWorkTab_workTabListEmptyBeforeGoingToTab() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ markWorkProfileUserAvailable();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
+ // The work list adapter must only be filled when we open the work tab
+ assertThat(activity.getWorkListAdapter().getCount(), is(0));
+ }
+
+ @Test
+ public void testWorkTab_workTabUsesExpectedAdapter() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ markWorkProfileUserAvailable();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+
+ assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
+ assertThat(activity.getWorkListAdapter().getCount(), is(4));
+ }
+
+ @Test
+ public void testWorkTab_personalTabUsesExpectedAdapter() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ markWorkProfileUserAvailable();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+
+ assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
+ assertThat(activity.getPersonalListAdapter().getCount(), is(3));
+ }
+
+ @Test
+ public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab))
+ .perform(click());
+
+ waitForIdle();
+ assertThat(activity.getWorkListAdapter().getCount(), is(4));
+ }
+
+ @Test
+ public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ ResolveInfo[] chosen = new ResolveInfo[1];
+ sOverrides.onSafelyStartCallback = targetInfo -> {
+ chosen[0] = targetInfo.getResolveInfo();
+ return true;
+ };
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab))
+ .perform(click());
+ waitForIdle();
+ // wait for the share sheet to expand
+ Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+ onView(first(allOf(withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ .perform(click());
+ onView(withId(R.id.button_once))
+ .perform(click());
+
+ waitForIdle();
+ assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
+ }
+
+ @Test
+ public void testWorkTab_noPersonalApps_workTabHasExpectedNumberOfTargets()
+ throws InterruptedException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+
+ final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab))
+ .perform(click());
+
+ waitForIdle();
+ assertThat(activity.getWorkListAdapter().getCount(), is(4));
+ }
+
+ @Ignore // b/148156663
+ @Test
+ public void testWorkTab_noPersonalApps_canStartWorkApps()
+ throws InterruptedException {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4);
+ when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ ResolveInfo[] chosen = new ResolveInfo[1];
+ sOverrides.onSafelyStartCallback = targetInfo -> {
+ chosen[0] = targetInfo.getResolveInfo();
+ return true;
+ };
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+ onView(withText(R.string.resolver_work_tab))
+ .perform(click());
+ waitForIdle();
+ // wait for the share sheet to expand
+ Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+ onView(first(allOf(withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ .perform(click());
+ onView(withId(R.id.button_once))
+ .perform(click());
+ waitForIdle();
+
+ assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
+ }
+
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -411,4 +635,8 @@ public class ResolverActivityTest {
private void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+
+ private void markWorkProfileUserAvailable() {
+ ResolverWrapperActivity.sOverrides.workProfileUserHandle = UserHandle.of(10);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index 59634f6d261c..d7db5f8e46eb 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -46,6 +46,12 @@ class ResolverDataProvider {
createResolverIntent(i), createResolveInfo(i, USER_SOMEONE_ELSE));
}
+ static ResolverActivity.ResolvedComponentInfo createResolvedComponentInfoWithOtherId(int i,
+ int userId) {
+ return new ResolverActivity.ResolvedComponentInfo(createComponentName(i),
+ createResolverIntent(i), createResolveInfo(i, userId));
+ }
+
static ComponentName createComponentName(int i) {
final String name = "component" + i;
return new ComponentName("foo.bar." + name, name);
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index c5d2cfaa9512..36c8724e522e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -17,12 +17,14 @@
package com.android.internal.app;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.os.UserHandle;
import com.android.internal.app.chooser.TargetInfo;
@@ -49,6 +51,17 @@ public class ResolverWrapperActivity extends ResolverActivity {
return (ResolverWrapperAdapter) mMultiProfilePagerAdapter.getActiveListAdapter();
}
+ ResolverListAdapter getPersonalListAdapter() {
+ return ((ResolverListAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(0));
+ }
+
+ ResolverListAdapter getWorkListAdapter() {
+ if (mMultiProfilePagerAdapter.getInactiveListAdapter() == null) {
+ return null;
+ }
+ return ((ResolverListAdapter) mMultiProfilePagerAdapter.getAdapterForIndex(1));
+ }
+
@Override
public boolean isVoiceInteraction() {
if (sOverrides.isVoiceInteraction != null) {
@@ -68,7 +81,12 @@ public class ResolverWrapperActivity extends ResolverActivity {
@Override
protected ResolverListController createListController(UserHandle userHandle) {
- return sOverrides.resolverListController;
+ if (userHandle == UserHandle.SYSTEM) {
+ when(sOverrides.resolverListController.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+ return sOverrides.resolverListController;
+ }
+ when(sOverrides.workResolverListController.getUserHandle()).thenReturn(userHandle);
+ return sOverrides.workResolverListController;
}
@Override
@@ -79,6 +97,20 @@ public class ResolverWrapperActivity extends ResolverActivity {
return super.getPackageManager();
}
+ protected UserHandle getCurrentUserHandle() {
+ return mMultiProfilePagerAdapter.getCurrentUserHandle();
+ }
+
+ @Override
+ protected UserHandle getWorkProfileUserHandle() {
+ return sOverrides.workProfileUserHandle;
+ }
+
+ @Override
+ public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ super.startActivityAsUser(intent, options, user);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -89,13 +121,17 @@ public class ResolverWrapperActivity extends ResolverActivity {
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public ResolverListController resolverListController;
+ public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
+ public UserHandle workProfileUserHandle;
public void reset() {
onSafelyStartCallback = null;
isVoiceInteraction = null;
createPackageManager = null;
resolverListController = mock(ResolverListController.class);
+ workResolverListController = mock(ResolverListController.class);
+ workProfileUserHandle = null;
}
}
} \ No newline at end of file
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index 1472b9034249..cd6b3af5fa6d 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -31,6 +31,9 @@ import static org.mockito.Mockito.mock;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
@@ -85,6 +88,13 @@ public final class ScreenshotHelperTest {
}
@Test
+ public void testProvidedImageScreenshot() {
+ mScreenshotHelper.provideScreenshot(
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888), new Rect(),
+ Insets.of(0, 0, 0, 0), 1, mHandler, null);
+ }
+
+ @Test
public void testScreenshotTimesOut() {
long timeoutMs = 10;
diff --git a/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index 36b282c87c40..4d9860387b8d 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -17,5 +17,6 @@
<permissions>
<privapp-permissions package="com.android.documentsui">
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 877ef2687349..0541db121ae6 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -60,10 +60,6 @@
<group gid="log" />
</permission>
- <permission name="android.permission.WRITE_MEDIA_STORAGE" >
- <group gid="media_rw" />
- </permission>
-
<permission name="android.permission.ACCESS_MTP" >
<group gid="mtp" />
</permission>
diff --git a/drm/java/android/drm/DrmConvertedStatus.java b/drm/java/android/drm/DrmConvertedStatus.java
index f6e570a76af0..0f7ceb4ba685 100644
--- a/drm/java/android/drm/DrmConvertedStatus.java
+++ b/drm/java/android/drm/DrmConvertedStatus.java
@@ -25,7 +25,9 @@ package android.drm;
* An valid offset value is provided only from a success call to
* {@link DrmManagerClient#closeConvertSession DrmManagerClient.closeConvertSession()}.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmConvertedStatus {
// The following status code constants must be in sync with
// DrmConvertedStatus.cpp. Please also update isValidStatusCode()
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
index c61819dacd99..f37c8accc84d 100644
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -22,7 +22,9 @@ import java.util.HashMap;
* An entity class that is passed to the
* {@link DrmManagerClient.OnErrorListener#onError onError()} callback.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmErrorEvent extends DrmEvent {
// Please add newly defined type constants to the end of the list,
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
index 1a19f5c62b94..e2fe87b55578 100644
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -21,7 +21,9 @@ import java.util.HashMap;
/**
* A base class that is used to send asynchronous event information from the DRM framework.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmEvent {
// Please do not add type constants in this class. More event type constants
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
index 8c43252e95b2..3240893a1f6c 100644
--- a/drm/java/android/drm/DrmInfo.java
+++ b/drm/java/android/drm/DrmInfo.java
@@ -30,7 +30,9 @@ import java.util.Iterator;
* The caller can retrieve the {@link DrmInfo} instance by passing a {@link DrmInfoRequest}
* instance to {@link DrmManagerClient#acquireDrmInfo}.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmInfo {
private byte[] mData;
private final String mMimeType;
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
index 2826dcee4f67..853f566cbe05 100644
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -22,7 +22,9 @@ import java.util.HashMap;
* An entity class that is passed to the
* {@link DrmManagerClient.OnInfoListener#onInfo onInfo()} callback.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmInfoEvent extends DrmEvent {
// Please add newly defined type constants to the end of the list,
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
index 621da413bf97..135bbc07e391 100644
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -24,7 +24,9 @@ import java.util.Iterator;
* class is passed to the {@link DrmManagerClient#acquireDrmInfo acquireDrmInfo()} method to get an
* instance of a {@link DrmInfo}.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmInfoRequest {
// Changes in following constants should be in sync with DrmInfoRequest.h
/**
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
index 9a3a7df66185..0fa1a708d52f 100644
--- a/drm/java/android/drm/DrmInfoStatus.java
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -25,7 +25,9 @@ package android.drm;
* This class contains the {@link ProcessedData} object, which can be used
* to instantiate a {@link DrmRights} object during license acquisition.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmInfoStatus {
// The following status code constants must be in sync with DrmInfoStatus.cpp
// Please update isValidStatusCode() if more status codes are added.
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 041300c4b1b0..ba3ebddd4b86 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -47,7 +47,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* The main programming interface for the DRM framework. An application must instantiate this class
* to access DRM agents through the DRM framework.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmManagerClient implements AutoCloseable {
/**
* Indicates that a request was successful or that no error occurred.
diff --git a/drm/java/android/drm/DrmOutputStream.java b/drm/java/android/drm/DrmOutputStream.java
index 9c238348846e..73e7f23b19c6 100644
--- a/drm/java/android/drm/DrmOutputStream.java
+++ b/drm/java/android/drm/DrmOutputStream.java
@@ -40,7 +40,9 @@ import java.net.UnknownServiceException;
* writing to disk, similar to a {@link FilterOutputStream}.
*
* @hide
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmOutputStream extends OutputStream {
private static final String TAG = "DrmOutputStream";
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
index 8747f777def0..0a8df090e64a 100644
--- a/drm/java/android/drm/DrmRights.java
+++ b/drm/java/android/drm/DrmRights.java
@@ -37,7 +37,9 @@ import java.util.Arrays;
* agent or plugin, they can be either null, or an empty string, or any other don't-care
* string value.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmRights {
private byte[] mData;
private String mMimeType;
diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java
index 3a77ea19a19b..98d4449eaf47 100644
--- a/drm/java/android/drm/DrmStore.java
+++ b/drm/java/android/drm/DrmStore.java
@@ -19,7 +19,9 @@ package android.drm;
/**
* Defines constants that are used by the DRM framework.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmStore {
/**
* Interface definition for the columns that represent DRM constraints.
diff --git a/drm/java/android/drm/DrmSupportInfo.java b/drm/java/android/drm/DrmSupportInfo.java
index 3694ff4304c4..f7e4fbdf50ff 100644
--- a/drm/java/android/drm/DrmSupportInfo.java
+++ b/drm/java/android/drm/DrmSupportInfo.java
@@ -26,7 +26,9 @@ import java.util.Iterator;
* Plug-in developers can expose the capability of their plug-in by passing an instance of this
* class to an application.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmSupportInfo {
private final ArrayList<String> mFileSuffixList = new ArrayList<String>();
private final ArrayList<String> mMimeTypeList = new ArrayList<String>();
diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java
index 60ee6d94949f..66a60cf90f11 100644
--- a/drm/java/android/drm/DrmUtils.java
+++ b/drm/java/android/drm/DrmUtils.java
@@ -33,7 +33,9 @@ import java.util.Iterator;
* constraints, the constraints will show up in the
* {@link DrmStore.ConstraintsColumns#EXTENDED_METADATA} key. You can use
* {@link DrmUtils.ExtendedMetadataParser} to iterate over those values.
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class DrmUtils {
/* Should be used when we need to read from local file */
/* package */ static byte[] readBytes(String path) throws IOException {
diff --git a/drm/java/android/drm/ProcessedData.java b/drm/java/android/drm/ProcessedData.java
index 06e03e73be91..35b728841a0c 100644
--- a/drm/java/android/drm/ProcessedData.java
+++ b/drm/java/android/drm/ProcessedData.java
@@ -23,7 +23,9 @@ package android.drm;
*
* In a license acquisition scenario this class holds the rights information in binary form.
*
+ * @deprecated Please use {@link android.media.MediaDrm}
*/
+@Deprecated
public class ProcessedData {
private final byte[] mData;
private String mAccountId = "_NO_USER";
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 4a252afc1df3..49817925d9b4 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -14,39 +14,41 @@
* limitations under the License.
*/
-X(Flush)
-X(Save)
-X(Restore)
+X(Flush)
+X(Save)
+X(Restore)
X(SaveLayer)
X(SaveBehind)
-X(Concat)
-X(SetMatrix)
+X(Concat44)
+X(Concat)
+X(SetMatrix)
+X(Scale)
X(Translate)
-X(ClipPath)
-X(ClipRect)
-X(ClipRRect)
+X(ClipPath)
+X(ClipRect)
+X(ClipRRect)
X(ClipRegion)
X(DrawPaint)
X(DrawBehind)
-X(DrawPath)
-X(DrawRect)
-X(DrawRegion)
-X(DrawOval)
+X(DrawPath)
+X(DrawRect)
+X(DrawRegion)
+X(DrawOval)
X(DrawArc)
-X(DrawRRect)
-X(DrawDRRect)
-X(DrawAnnotation)
-X(DrawDrawable)
+X(DrawRRect)
+X(DrawDRRect)
+X(DrawAnnotation)
+X(DrawDrawable)
X(DrawPicture)
-X(DrawImage)
-X(DrawImageNine)
-X(DrawImageRect)
+X(DrawImage)
+X(DrawImageNine)
+X(DrawImageRect)
X(DrawImageLattice)
X(DrawTextBlob)
-X(DrawPatch)
-X(DrawPoints)
-X(DrawVertices)
-X(DrawAtlas)
+X(DrawPatch)
+X(DrawPoints)
+X(DrawVertices)
+X(DrawAtlas)
X(DrawShadowRec)
X(DrawVectorDrawable)
X(DrawWebView)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index c0df2faf120a..dc467c41baed 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -130,6 +130,12 @@ struct SaveBehind final : Op {
}
};
+struct Concat44 final : Op {
+ static const auto kType = Type::Concat44;
+ Concat44(const SkScalar m[16]) { memcpy(colMajor, m, sizeof(colMajor)); }
+ SkScalar colMajor[16];
+ void draw(SkCanvas* c, const SkMatrix&) const { c->experimental_concat44(colMajor); }
+};
struct Concat final : Op {
static const auto kType = Type::Concat;
Concat(const SkMatrix& matrix) : matrix(matrix) {}
@@ -144,6 +150,12 @@ struct SetMatrix final : Op {
c->setMatrix(SkMatrix::Concat(original, matrix));
}
};
+struct Scale final : Op {
+ static const auto kType = Type::Scale;
+ Scale(SkScalar sx, SkScalar sy) : sx(sx), sy(sy) {}
+ SkScalar sx, sy;
+ void draw(SkCanvas* c, const SkMatrix&) const { c->scale(sx, sy); }
+};
struct Translate final : Op {
static const auto kType = Type::Translate;
Translate(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {}
@@ -562,12 +574,18 @@ void DisplayListData::saveBehind(const SkRect* subset) {
this->push<SaveBehind>(0, subset);
}
+void DisplayListData::concat44(const SkScalar colMajor[16]) {
+ this->push<Concat44>(0, colMajor);
+}
void DisplayListData::concat(const SkMatrix& matrix) {
this->push<Concat>(0, matrix);
}
void DisplayListData::setMatrix(const SkMatrix& matrix) {
this->push<SetMatrix>(0, matrix);
}
+void DisplayListData::scale(SkScalar sx, SkScalar sy) {
+ this->push<Scale>(0, sx, sy);
+}
void DisplayListData::translate(SkScalar dx, SkScalar dy) {
this->push<Translate>(0, dx, dy);
}
@@ -823,12 +841,18 @@ bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) {
return false;
}
+void RecordingCanvas::didConcat44(const SkScalar colMajor[16]) {
+ fDL->concat44(colMajor);
+}
void RecordingCanvas::didConcat(const SkMatrix& matrix) {
fDL->concat(matrix);
}
void RecordingCanvas::didSetMatrix(const SkMatrix& matrix) {
fDL->setMatrix(matrix);
}
+void RecordingCanvas::didScale(SkScalar sx, SkScalar sy) {
+ fDL->scale(sx, sy);
+}
void RecordingCanvas::didTranslate(SkScalar dx, SkScalar dy) {
fDL->translate(dx, dy);
}
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 322eff24dd34..7eb1ce3eb18a 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -82,8 +82,10 @@ private:
void saveBehind(const SkRect*);
void restore();
+ void concat44(const SkScalar colMajor[16]);
void concat(const SkMatrix&);
void setMatrix(const SkMatrix&);
+ void scale(SkScalar, SkScalar);
void translate(SkScalar, SkScalar);
void translateZ(SkScalar);
@@ -153,8 +155,10 @@ public:
void onFlush() override;
+ void didConcat44(const SkScalar[16]) override;
void didConcat(const SkMatrix&) override;
void didSetMatrix(const SkMatrix&) override;
+ void didScale(SkScalar, SkScalar) override;
void didTranslate(SkScalar, SkScalar) override;
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index a1b2b18195bc..aa8849b642b1 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -26,6 +26,7 @@
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
#include "SkRect.h"
+#include "include/private/SkM44.h"
namespace android {
namespace uirenderer {
@@ -92,7 +93,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds();
SkIRect clipBounds = canvas->getDeviceClipBounds();
- SkMatrix44 mat4(canvas->getTotalMatrix());
+ SkM44 mat4(canvas->experimental_getLocalToDevice());
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
@@ -118,7 +119,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
// update the matrix and clip that we pass to the WebView to match the coordinates of
// the offscreen layer
- mat4.preTranslate(-clipBounds.fLeft, -clipBounds.fTop, 0);
+ mat4.preTranslate(-clipBounds.fLeft, -clipBounds.fTop);
clipBounds.offsetTo(0, 0);
clipRegion.translate(-surfaceBounds.fLeft, -surfaceBounds.fTop);
@@ -126,7 +127,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
// we are drawing into a (clipped) offscreen layer so we must update the clip and matrix
// from device coordinates to the layer's coordinates
clipBounds.offset(-surfaceBounds.fLeft, -surfaceBounds.fTop);
- mat4.preTranslate(-surfaceBounds.fLeft, -surfaceBounds.fTop, 0);
+ mat4.preTranslate(-surfaceBounds.fLeft, -surfaceBounds.fTop);
}
DrawGlInfo info;
@@ -137,7 +138,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
info.isLayer = fboID != 0;
info.width = fboSize.width();
info.height = fboSize.height();
- mat4.asColMajorf(&info.transform[0]);
+ mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
// ensure that the framebuffer that the webview will render into is bound before we clear
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 112792611fc3..68f111752a4c 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -20,6 +20,7 @@
#include <GrBackendDrawableInfo.h>
#include <SkAndroidFrameworkUtils.h>
#include <SkImage.h>
+#include "include/private/SkM44.h"
#include <utils/Color.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
@@ -62,7 +63,7 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
renderthread::RenderThread::getInstance().vulkanManager();
mFunctorHandle->initVk(vk_manager.getVkFunctorInitParams());
- SkMatrix44 mat4(mMatrix);
+ SkM44 mat4(mMatrix);
VkFunctorDrawParams params{
.width = mImageInfo.width(),
.height = mImageInfo.height(),
@@ -72,7 +73,7 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
.clip_right = mClip.fRight,
.clip_bottom = mClip.fBottom,
};
- mat4.asColMajorf(&params.transform[0]);
+ mat4.getColMajor(&params.transform[0]);
params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
params.color_attachment_index = vulkan_info.fColorAttachmentIndex;
params.compatible_render_pass = vulkan_info.fCompatibleRenderPass;
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 706325f00bd2..241d3708def5 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -121,7 +121,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
glBindTexture(GL_TEXTURE_2D, 0);
DrawGlInfo info;
- SkMatrix44 mat4(canvas->getTotalMatrix());
+ SkM44 mat4(canvas->experimental_getLocalToDevice());
SkIRect clipBounds = canvas->getDeviceClipBounds();
info.clipLeft = clipBounds.fLeft;
@@ -131,7 +131,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
info.isLayer = true;
info.width = mFBInfo.width();
info.height = mFBInfo.height();
- mat4.asColMajorf(&info.transform[0]);
+ mat4.getColMajor(&info.transform[0]);
info.color_space_ptr = canvas->imageInfo().colorSpace();
glViewport(0, 0, info.width, info.height);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 52305b8244a6..ebc622bae302 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -100,6 +100,7 @@ public:
virtual int32_t getDisplayId() const;
virtual void fade(Transition transition);
virtual void unfade(Transition transition);
+ virtual void setDisplayViewport(const DisplayViewport& viewport);
virtual void setPresentation(Presentation presentation);
virtual void setSpots(const PointerCoords* spotCoords,
@@ -108,7 +109,6 @@ public:
void updatePointerIcon(int32_t iconId);
void setCustomPointerIcon(const SpriteIcon& icon);
- void setDisplayViewport(const DisplayViewport& viewport);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void reloadPointerResources();
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 8a7878b46e89..ed4bf1b2d53e 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -17,6 +17,7 @@
package android.location;
import android.annotation.FloatRange;
+import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -39,6 +40,9 @@ public final class GnssClock implements Parcelable {
private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
private static final int HAS_ELAPSED_REALTIME_NANOS = (1 << 7);
private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS = (1 << 8);
+ private static final int HAS_REFERENCE_CONSTELLATION_TYPE_FOR_ISB = (1 << 9);
+ private static final int HAS_REFERENCE_CARRIER_FREQUENCY_FOR_ISB = (1 << 10);
+ private static final int HAS_REFERENCE_CODE_TYPE_FOR_ISB = (1 << 11);
// End enumerations in sync with gps.h
@@ -54,6 +58,9 @@ public final class GnssClock implements Parcelable {
private int mHardwareClockDiscontinuityCount;
private long mElapsedRealtimeNanos;
private double mElapsedRealtimeUncertaintyNanos;
+ private int mReferenceConstellationTypeForIsb;
+ private double mReferenceCarrierFrequencyHzForIsb;
+ private String mReferenceCodeTypeForIsb;
/**
* @hide
@@ -81,6 +88,9 @@ public final class GnssClock implements Parcelable {
mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
mElapsedRealtimeNanos = clock.mElapsedRealtimeNanos;
mElapsedRealtimeUncertaintyNanos = clock.mElapsedRealtimeUncertaintyNanos;
+ mReferenceConstellationTypeForIsb = clock.mReferenceConstellationTypeForIsb;
+ mReferenceCarrierFrequencyHzForIsb = clock.mReferenceCarrierFrequencyHzForIsb;
+ mReferenceCodeTypeForIsb = clock.mReferenceCodeTypeForIsb;
}
/**
@@ -196,7 +206,6 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetTimeUncertaintyNanos() {
resetFlag(HAS_TIME_UNCERTAINTY);
- mTimeUncertaintyNanos = Double.NaN;
}
/**
@@ -286,7 +295,6 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetBiasNanos() {
resetFlag(HAS_BIAS);
- mBiasNanos = Double.NaN;
}
/**
@@ -327,7 +335,6 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetBiasUncertaintyNanos() {
resetFlag(HAS_BIAS_UNCERTAINTY);
- mBiasUncertaintyNanos = Double.NaN;
}
/**
@@ -371,7 +378,6 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetDriftNanosPerSecond() {
resetFlag(HAS_DRIFT);
- mDriftNanosPerSecond = Double.NaN;
}
/**
@@ -411,7 +417,6 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetDriftUncertaintyNanosPerSecond() {
resetFlag(HAS_DRIFT_UNCERTAINTY);
- mDriftUncertaintyNanosPerSecond = Double.NaN;
}
/**
@@ -495,7 +500,128 @@ public final class GnssClock implements Parcelable {
@TestApi
public void resetElapsedRealtimeUncertaintyNanos() {
resetFlag(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
- mElapsedRealtimeUncertaintyNanos = Double.NaN;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReferenceConstellationTypeForIsb()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasReferenceConstellationTypeForIsb() {
+ return isFlagSet(HAS_REFERENCE_CONSTELLATION_TYPE_FOR_ISB);
+ }
+
+ /**
+ * Returns the reference constellation type for inter-signal bias.
+ *
+ * <p>The value is only available if {@link #hasReferenceConstellationTypeForIsb()} is
+ * {@code true}.
+ *
+ * <p>The return value is one of those constants with {@code CONSTELLATION_} prefix in
+ * {@link GnssStatus}.
+ */
+ @GnssStatus.ConstellationType
+ public int getReferenceConstellationTypeForIsb() {
+ return mReferenceConstellationTypeForIsb;
+ }
+
+ /**
+ * Sets the reference constellation type for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void setReferenceConstellationTypeForIsb(@GnssStatus.ConstellationType int value) {
+ setFlag(HAS_REFERENCE_CONSTELLATION_TYPE_FOR_ISB);
+ mReferenceConstellationTypeForIsb = value;
+ }
+
+ /**
+ * Resets the reference constellation type for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void resetReferenceConstellationTypeForIsb() {
+ resetFlag(HAS_REFERENCE_CONSTELLATION_TYPE_FOR_ISB);
+ mReferenceConstellationTypeForIsb = GnssStatus.CONSTELLATION_UNKNOWN;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReferenceCarrierFrequencyHzForIsb()} is available, {@code
+ * false} otherwise.
+ */
+ public boolean hasReferenceCarrierFrequencyHzForIsb() {
+ return isFlagSet(HAS_REFERENCE_CARRIER_FREQUENCY_FOR_ISB);
+ }
+
+ /**
+ * Returns the reference carrier frequency in Hz for inter-signal bias.
+ *
+ * <p>The value is only available if {@link #hasReferenceCarrierFrequencyHzForIsb()} is
+ * {@code true}.
+ */
+ @FloatRange(from = 0.0)
+ public double getReferenceCarrierFrequencyHzForIsb() {
+ return mReferenceCarrierFrequencyHzForIsb;
+ }
+
+ /**
+ * Sets the reference carrier frequency in Hz for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from = 0.0) double value) {
+ setFlag(HAS_REFERENCE_CARRIER_FREQUENCY_FOR_ISB);
+ mReferenceCarrierFrequencyHzForIsb = value;
+ }
+
+ /**
+ * Resets the reference carrier frequency in Hz for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void resetReferenceCarrierFrequencyHzForIsb() {
+ resetFlag(HAS_REFERENCE_CARRIER_FREQUENCY_FOR_ISB);
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReferenceCodeTypeForIsb()} is available, {@code
+ * false} otherwise.
+ */
+ public boolean hasReferenceCodeTypeForIsb() {
+ return isFlagSet(HAS_REFERENCE_CODE_TYPE_FOR_ISB);
+ }
+
+ /**
+ * Returns the reference code type for inter-signal bias.
+ *
+ * <p>The value is only available if {@link #hasReferenceCodeTypeForIsb()} is
+ * {@code true}.
+ *
+ * <p>The return value is one of those constants defined in
+ * {@link GnssMeasurement#getCodeType()}.
+ */
+ @NonNull
+ public String getReferenceCodeTypeForIsb() {
+ return mReferenceCodeTypeForIsb;
+ }
+
+ /**
+ * Sets the reference code type for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void setReferenceCodeTypeForIsb(@NonNull String codeType) {
+ setFlag(HAS_REFERENCE_CODE_TYPE_FOR_ISB);
+ mReferenceCodeTypeForIsb = codeType;
+ }
+
+ /**
+ * Resets the reference code type for inter-signal bias.
+ * @hide
+ */
+ @TestApi
+ public void resetReferenceCodeTypeForIsb() {
+ resetFlag(HAS_REFERENCE_CODE_TYPE_FOR_ISB);
+ mReferenceCodeTypeForIsb = "UNKNOWN";
}
/**
@@ -543,6 +669,9 @@ public final class GnssClock implements Parcelable {
gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
gpsClock.mElapsedRealtimeNanos = parcel.readLong();
gpsClock.mElapsedRealtimeUncertaintyNanos = parcel.readDouble();
+ gpsClock.mReferenceConstellationTypeForIsb = parcel.readInt();
+ gpsClock.mReferenceCarrierFrequencyHzForIsb = parcel.readDouble();
+ gpsClock.mReferenceCodeTypeForIsb = parcel.readString();
return gpsClock;
}
@@ -567,6 +696,9 @@ public final class GnssClock implements Parcelable {
parcel.writeInt(mHardwareClockDiscontinuityCount);
parcel.writeLong(mElapsedRealtimeNanos);
parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
+ parcel.writeInt(mReferenceConstellationTypeForIsb);
+ parcel.writeDouble(mReferenceCarrierFrequencyHzForIsb);
+ parcel.writeString(mReferenceCodeTypeForIsb);
}
@Override
@@ -580,7 +712,9 @@ public final class GnssClock implements Parcelable {
final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n";
StringBuilder builder = new StringBuilder("GnssClock:\n");
- builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
+ if (hasLeapSecond()) {
+ builder.append(String.format(format, "LeapSecond", mLeapSecond));
+ }
builder.append(String.format(
formatWithUncertainty,
@@ -589,39 +723,57 @@ public final class GnssClock implements Parcelable {
"TimeUncertaintyNanos",
hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
- builder.append(String.format(
- format,
- "FullBiasNanos",
- hasFullBiasNanos() ? mFullBiasNanos : null));
+ if (hasFullBiasNanos()) {
+ builder.append(String.format(format, "FullBiasNanos", mFullBiasNanos));
+ }
- builder.append(String.format(
- formatWithUncertainty,
- "BiasNanos",
- hasBiasNanos() ? mBiasNanos : null,
- "BiasUncertaintyNanos",
- hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
+ if (hasBiasNanos() || hasBiasUncertaintyNanos()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "BiasNanos",
+ hasBiasNanos() ? mBiasNanos : null,
+ "BiasUncertaintyNanos",
+ hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
+ }
- builder.append(String.format(
- formatWithUncertainty,
- "DriftNanosPerSecond",
- hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
- "DriftUncertaintyNanosPerSecond",
- hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
+ if (hasDriftNanosPerSecond() || hasDriftUncertaintyNanosPerSecond()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "DriftNanosPerSecond",
+ hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
+ "DriftUncertaintyNanosPerSecond",
+ hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
+ }
builder.append(String.format(
format,
"HardwareClockDiscontinuityCount",
mHardwareClockDiscontinuityCount));
- builder.append(String.format(
- format,
- "ElapsedRealtimeNanos",
- hasElapsedRealtimeNanos() ? mElapsedRealtimeNanos : null));
+ if (hasElapsedRealtimeNanos() || hasElapsedRealtimeUncertaintyNanos()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "ElapsedRealtimeNanos",
+ hasElapsedRealtimeNanos() ? mElapsedRealtimeNanos : null,
+ "ElapsedRealtimeUncertaintyNanos",
+ hasElapsedRealtimeUncertaintyNanos() ? mElapsedRealtimeUncertaintyNanos
+ : null));
+ }
- builder.append(String.format(
- format,
- "ElapsedRealtimeUncertaintyNanos",
- hasElapsedRealtimeUncertaintyNanos() ? mElapsedRealtimeUncertaintyNanos : null));
+ if (hasReferenceConstellationTypeForIsb()) {
+ builder.append(String.format(format, "ReferenceConstellationTypeForIsb",
+ mReferenceConstellationTypeForIsb));
+ }
+
+ if (hasReferenceCarrierFrequencyHzForIsb()) {
+ builder.append(String.format(format, "ReferenceCarrierFrequencyHzForIsb",
+ mReferenceCarrierFrequencyHzForIsb));
+ }
+
+ if (hasReferenceCodeTypeForIsb()) {
+ builder.append(
+ String.format(format, "ReferenceCodeTypeForIsb", mReferenceCodeTypeForIsb));
+ }
return builder.toString();
}
@@ -639,6 +791,9 @@ public final class GnssClock implements Parcelable {
setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
resetElapsedRealtimeNanos();
resetElapsedRealtimeUncertaintyNanos();
+ resetReferenceConstellationTypeForIsb();
+ resetReferenceCarrierFrequencyHzForIsb();
+ resetReferenceCodeTypeForIsb();
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 3eeb3a2051e9..83a8995bee13 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,11 +16,21 @@
package android.location;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_AUTOMATIC_GAIN_CONTROL;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_CYCLES;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_FREQUENCY;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_PHASE;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_PHASE_UNCERTAINTY;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_RECEIVER_ISB;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_RECEIVER_ISB_UNCERTAINTY;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SATELLITE_ISB;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SATELLITE_ISB_UNCERTAINTY;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SNR;
+
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.hardware.gnss.V1_0.IGnssMeasurementCallback.GnssMeasurementFlags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -53,19 +63,14 @@ public final class GnssMeasurement implements Parcelable {
private double mSnrInDb;
private double mAutomaticGainControlLevelInDb;
@NonNull private String mCodeType;
+ private double mReceiverInterSignalBiasNanos;
+ private double mReceiverInterSignalBiasUncertaintyNanos;
+ private double mSatelliteInterSignalBiasNanos;
+ private double mSatelliteInterSignalBiasUncertaintyNanos;
// The following enumerations must be in sync with the values declared in GNSS HAL.
private static final int HAS_NO_FLAGS = 0;
- private static final int HAS_SNR = GnssMeasurementFlags.HAS_SNR;
- private static final int HAS_CARRIER_FREQUENCY = GnssMeasurementFlags.HAS_CARRIER_FREQUENCY;
- private static final int HAS_CARRIER_CYCLES = GnssMeasurementFlags.HAS_CARRIER_CYCLES;
- private static final int HAS_CARRIER_PHASE = GnssMeasurementFlags.HAS_CARRIER_PHASE;
- private static final int HAS_CARRIER_PHASE_UNCERTAINTY =
- GnssMeasurementFlags.HAS_CARRIER_PHASE_UNCERTAINTY;
- private static final int HAS_AUTOMATIC_GAIN_CONTROL =
- GnssMeasurementFlags.HAS_AUTOMATIC_GAIN_CONTROL;
-
private static final int HAS_CODE_TYPE = (1 << 14);
private static final int HAS_BASEBAND_CN0 = (1 << 15);
@@ -263,6 +268,12 @@ public final class GnssMeasurement implements Parcelable {
mSnrInDb = measurement.mSnrInDb;
mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
mCodeType = measurement.mCodeType;
+ mReceiverInterSignalBiasNanos = measurement.mReceiverInterSignalBiasNanos;
+ mReceiverInterSignalBiasUncertaintyNanos =
+ measurement.mReceiverInterSignalBiasUncertaintyNanos;
+ mSatelliteInterSignalBiasNanos = measurement.mSatelliteInterSignalBiasNanos;
+ mSatelliteInterSignalBiasUncertaintyNanos =
+ measurement.mSatelliteInterSignalBiasUncertaintyNanos;
}
/**
@@ -838,7 +849,6 @@ public final class GnssMeasurement implements Parcelable {
@TestApi
public void resetBasebandCn0DbHz() {
resetFlag(HAS_BASEBAND_CN0);
- mBasebandCn0DbHz = Double.NaN;
}
/**
@@ -1169,7 +1179,6 @@ public final class GnssMeasurement implements Parcelable {
@Deprecated
public void resetCarrierPhase() {
resetFlag(HAS_CARRIER_PHASE);
- mCarrierPhase = Double.NaN;
}
/**
@@ -1224,7 +1233,6 @@ public final class GnssMeasurement implements Parcelable {
@Deprecated
public void resetCarrierPhaseUncertainty() {
resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
- mCarrierPhaseUncertainty = Double.NaN;
}
/**
@@ -1295,7 +1303,6 @@ public final class GnssMeasurement implements Parcelable {
@TestApi
public void resetSnrInDb() {
resetFlag(HAS_SNR);
- mSnrInDb = Double.NaN;
}
/**
@@ -1343,7 +1350,6 @@ public final class GnssMeasurement implements Parcelable {
@TestApi
public void resetAutomaticGainControlLevel() {
resetFlag(HAS_AUTOMATIC_GAIN_CONTROL);
- mAutomaticGainControlLevelInDb = Double.NaN;
}
/**
@@ -1428,7 +1434,200 @@ public final class GnssMeasurement implements Parcelable {
mCodeType = "UNKNOWN";
}
- public static final @android.annotation.NonNull Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
+ /**
+ * Returns {@code true} if {@link #getReceiverInterSignalBiasNanos()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasReceiverInterSignalBiasNanos() {
+ return isFlagSet(HAS_RECEIVER_ISB);
+ }
+
+ /**
+ * Gets the GNSS measurement's receiver inter-signal bias in nanoseconds with sub-nanosecond
+ * accuracy.
+ *
+ * <p>This value is the estimated receiver-side inter-system (different from the
+ * constellation in {@link GnssClock#getReferenceConstellationTypeForIsb()} bias and
+ * inter-frequency (different from the carrier frequency in
+ * {@link GnssClock#getReferenceCarrierFrequencyHzForIsb()}) bias. The reported receiver
+ * inter-signal bias must include signal delays caused by:
+ *
+ * <ul>
+ * <li>Receiver inter-constellation bias</li>
+ * <li>Receiver inter-frequency bias</li>
+ * <li>Receiver inter-code bias</li>
+ * </ul>
+ *
+ * <p>The value does not include the inter-frequency Ionospheric bias.
+ *
+ * <p>The value is only available if {@link #hasReceiverInterSignalBiasNanos()} is {@code true}.
+ */
+ public double getReceiverInterSignalBiasNanos() {
+ return mReceiverInterSignalBiasNanos;
+ }
+
+ /**
+ * Sets the GNSS measurement's receiver inter-signal bias in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setReceiverInterSignalBiasNanos(double receiverInterSignalBiasNanos) {
+ setFlag(HAS_RECEIVER_ISB);
+ mReceiverInterSignalBiasNanos = receiverInterSignalBiasNanos;
+ }
+
+ /**
+ * Resets the GNSS measurement's receiver inter-signal bias in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetReceiverInterSignalBiasNanos() {
+ resetFlag(HAS_RECEIVER_ISB);
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReceiverInterSignalBiasUncertaintyNanos()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasReceiverInterSignalBiasUncertaintyNanos() {
+ return isFlagSet(HAS_RECEIVER_ISB_UNCERTAINTY);
+ }
+
+ /**
+ * Gets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in
+ * nanoseconds with sub-nanosecond accuracy.
+ *
+ * <p>The value is only available if {@link #hasReceiverInterSignalBiasUncertaintyNanos()} is
+ * {@code true}.
+ */
+ @FloatRange(from = 0.0)
+ public double getReceiverInterSignalBiasUncertaintyNanos() {
+ return mReceiverInterSignalBiasUncertaintyNanos;
+ }
+
+ /**
+ * Sets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setReceiverInterSignalBiasUncertaintyNanos(@FloatRange(from = 0.0)
+ double receiverInterSignalBiasUncertaintyNanos) {
+ setFlag(HAS_RECEIVER_ISB_UNCERTAINTY);
+ mReceiverInterSignalBiasUncertaintyNanos = receiverInterSignalBiasUncertaintyNanos;
+ }
+
+ /**
+ * Resets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in
+ * nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetReceiverInterSignalBiasUncertaintyNanos() {
+ resetFlag(HAS_RECEIVER_ISB_UNCERTAINTY);
+ }
+
+ /**
+ * Returns {@code true} if {@link #getSatelliteInterSignalBiasNanos()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasSatelliteInterSignalBiasNanos() {
+ return isFlagSet(HAS_SATELLITE_ISB);
+ }
+
+ /**
+ * Gets the GNSS measurement's satellite inter-signal bias in nanoseconds with sub-nanosecond
+ * accuracy.
+ *
+ * <p>This value is the satellite-and-control-segment-side inter-system (different from the
+ * constellation in {@link GnssClock#getReferenceConstellationTypeForIsb()}) bias and
+ * inter-frequency (different from the carrier frequency in
+ * {@link GnssClock#getReferenceCarrierFrequencyHzForIsb()}) bias, including:
+ *
+ * <ul>
+ * <li>Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
+ * BDS-GLO Time Offset (BGTO))</li>
+ * <li>Group delay (e.g., Total Group Delay (TGD))</li>
+ * <li>Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
+ * and satellite inter-code bias (e.g., Differential Code Bias (DCB)).</li>
+ * </ul>
+ *
+ * <p>The value is only available if {@link #hasSatelliteInterSignalBiasNanos()} is {@code
+ * true}.
+ */
+ public double getSatelliteInterSignalBiasNanos() {
+ return mSatelliteInterSignalBiasNanos;
+ }
+
+ /**
+ * Sets the GNSS measurement's satellite inter-signal bias in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setSatelliteInterSignalBiasNanos(double satelliteInterSignalBiasNanos) {
+ setFlag(HAS_SATELLITE_ISB);
+ mSatelliteInterSignalBiasNanos = satelliteInterSignalBiasNanos;
+ }
+
+ /**
+ * Resets the GNSS measurement's satellite inter-signal bias in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetSatelliteInterSignalBiasNanos() {
+ resetFlag(HAS_SATELLITE_ISB);
+ }
+
+ /**
+ * Returns {@code true} if {@link #getSatelliteInterSignalBiasUncertaintyNanos()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasSatelliteInterSignalBiasUncertaintyNanos() {
+ return isFlagSet(HAS_SATELLITE_ISB_UNCERTAINTY);
+ }
+
+ /**
+ * Gets the GNSS measurement's satellite inter-signal bias uncertainty (1 sigma) in
+ * nanoseconds with sub-nanosecond accuracy.
+ *
+ * <p>The value is only available if {@link #hasSatelliteInterSignalBiasUncertaintyNanos()} is
+ * {@code true}.
+ */
+ @FloatRange(from = 0.0)
+ public double getSatelliteInterSignalBiasUncertaintyNanos() {
+ return mSatelliteInterSignalBiasUncertaintyNanos;
+ }
+
+ /**
+ * Sets the GNSS measurement's satellite inter-signal bias uncertainty (1 sigma) in nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from = 0.0)
+ double satelliteInterSignalBiasUncertaintyNanos) {
+ setFlag(HAS_SATELLITE_ISB_UNCERTAINTY);
+ mSatelliteInterSignalBiasUncertaintyNanos = satelliteInterSignalBiasUncertaintyNanos;
+ }
+
+ /**
+ * Resets the GNSS measurement's satellite inter-signal bias uncertainty (1 sigma) in
+ * nanoseconds.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetSatelliteInterSignalBiasUncertaintyNanos() {
+ resetFlag(HAS_SATELLITE_ISB_UNCERTAINTY);
+ }
+
+
+ public static final @NonNull Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
GnssMeasurement gnssMeasurement = new GnssMeasurement();
@@ -1455,6 +1654,10 @@ public final class GnssMeasurement implements Parcelable {
gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
gnssMeasurement.mCodeType = parcel.readString();
gnssMeasurement.mBasebandCn0DbHz = parcel.readDouble();
+ gnssMeasurement.mReceiverInterSignalBiasNanos = parcel.readDouble();
+ gnssMeasurement.mReceiverInterSignalBiasUncertaintyNanos = parcel.readDouble();
+ gnssMeasurement.mSatelliteInterSignalBiasNanos = parcel.readDouble();
+ gnssMeasurement.mSatelliteInterSignalBiasUncertaintyNanos = parcel.readDouble();
return gnssMeasurement;
}
@@ -1489,6 +1692,10 @@ public final class GnssMeasurement implements Parcelable {
parcel.writeDouble(mAutomaticGainControlLevelInDb);
parcel.writeString(mCodeType);
parcel.writeDouble(mBasebandCn0DbHz);
+ parcel.writeDouble(mReceiverInterSignalBiasNanos);
+ parcel.writeDouble(mReceiverInterSignalBiasUncertaintyNanos);
+ parcel.writeDouble(mSatelliteInterSignalBiasNanos);
+ parcel.writeDouble(mSatelliteInterSignalBiasUncertaintyNanos);
}
@Override
@@ -1517,8 +1724,9 @@ public final class GnssMeasurement implements Parcelable {
builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
- builder.append(String.format(format, "BasebandCn0DbHz",
- hasBasebandCn0DbHz() ? mBasebandCn0DbHz : null));
+ if (hasBasebandCn0DbHz()) {
+ builder.append(String.format(format, "BasebandCn0DbHz", mBasebandCn0DbHz));
+ }
builder.append(String.format(
formatWithUncertainty,
@@ -1539,37 +1747,57 @@ public final class GnssMeasurement implements Parcelable {
"AccumulatedDeltaRangeUncertaintyMeters",
mAccumulatedDeltaRangeUncertaintyMeters));
- builder.append(String.format(
- format,
- "CarrierFrequencyHz",
- hasCarrierFrequencyHz() ? mCarrierFrequencyHz : null));
+ if (hasCarrierFrequencyHz()) {
+ builder.append(String.format(format, "CarrierFrequencyHz", mCarrierFrequencyHz));
+ }
- builder.append(String.format(
- format,
- "CarrierCycles",
- hasCarrierCycles() ? mCarrierCycles : null));
+ if (hasCarrierCycles()) {
+ builder.append(String.format(format, "CarrierCycles", mCarrierCycles));
+ }
- builder.append(String.format(
- formatWithUncertainty,
- "CarrierPhase",
- hasCarrierPhase() ? mCarrierPhase : null,
- "CarrierPhaseUncertainty",
- hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
+ if (hasCarrierPhase() || hasCarrierPhaseUncertainty()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "CarrierPhase",
+ hasCarrierPhase() ? mCarrierPhase : null,
+ "CarrierPhaseUncertainty",
+ hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
+ }
builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
- builder.append(String.format(
- format,
- "SnrInDb",
- hasSnrInDb() ? mSnrInDb : null));
- builder.append(String.format(
- format,
- "AgcLevelDb",
- hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
- builder.append(String.format(
- format,
- "CodeType",
- hasCodeType() ? mCodeType : null));
+ if (hasSnrInDb()) {
+ builder.append(String.format(format, "SnrInDb", mSnrInDb));
+ }
+
+ if (hasAutomaticGainControlLevelDb()) {
+ builder.append(String.format(format, "AgcLevelDb", mAutomaticGainControlLevelInDb));
+ }
+
+ if (hasCodeType()) {
+ builder.append(String.format(format, "CodeType", mCodeType));
+ }
+
+ if (hasReceiverInterSignalBiasNanos() || hasReceiverInterSignalBiasUncertaintyNanos()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "ReceiverInterSignalBiasNs",
+ hasReceiverInterSignalBiasNanos() ? mReceiverInterSignalBiasNanos : null,
+ "ReceiverInterSignalBiasUncertaintyNs",
+ hasReceiverInterSignalBiasUncertaintyNanos()
+ ? mReceiverInterSignalBiasUncertaintyNanos : null));
+ }
+
+ if (hasSatelliteInterSignalBiasNanos() || hasSatelliteInterSignalBiasUncertaintyNanos()) {
+ builder.append(String.format(
+ formatWithUncertainty,
+ "SatelliteInterSignalBiasNs",
+ hasSatelliteInterSignalBiasNanos() ? mSatelliteInterSignalBiasNanos : null,
+ "SatelliteInterSignalBiasUncertaintyNs",
+ hasSatelliteInterSignalBiasUncertaintyNanos()
+ ? mSatelliteInterSignalBiasUncertaintyNanos
+ : null));
+ }
return builder.toString();
}
@@ -1596,6 +1824,10 @@ public final class GnssMeasurement implements Parcelable {
resetAutomaticGainControlLevel();
resetCodeType();
resetBasebandCn0DbHz();
+ resetReceiverInterSignalBiasNanos();
+ resetReceiverInterSignalBiasUncertaintyNanos();
+ resetSatelliteInterSignalBiasNanos();
+ resetSatelliteInterSignalBiasUncertaintyNanos();
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 89a3bc070578..f17fa399dace 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -189,6 +189,7 @@ public final class GnssStatus {
* <li>QZSS: 193-200</li>
* <li>Galileo: 1-36</li>
* <li>Beidou: 1-37</li>
+ * <li>IRNSS: 1-14</li>
* </ul>
*
* @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index b2314c585e6e..572fbc373730 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -118,6 +118,7 @@ public final class ProviderRequest implements Parcelable {
for (LocationRequest request : locationRequests) {
request.writeToParcel(parcel, flags);
}
+ parcel.writeParcelable(workSource, flags);
}
@Override
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index cb132f5b1101..6e63d1704fcb 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -422,6 +422,40 @@ public final class AudioDeviceInfo {
return AudioFormat.filterPublicFormats(mPort.formats());
}
+ /**
+ * Returns an array of supported encapsulation modes for the device.
+ *
+ * The array can include any of
+ * {@link AudioTrack#ENCAPSULATION_MODE_ELEMENTARY_STREAM},
+ * {@link AudioTrack#ENCAPSULATION_MODE_HANDLE}.
+ *
+ * @return An array of supported encapsulation modes for the device. This
+ * may be an empty array if no encapsulation modes are supported.
+ */
+ public @NonNull int[] getEncapsulationModes() {
+ // Implement a getter in r-dev or r-tv-dev as needed.
+ return new int[0]; // be careful of returning a copy of any internal data.
+ }
+
+ /**
+ * Returns an array of supported encapsulation metadata types for the device.
+ *
+ * The metadata type returned should be allowed for all encapsulation modes supported
+ * by the device. Some metadata types may apply only to certain
+ * compressed stream formats, the returned list is the union of subsets.
+ *
+ * The array can include any of
+ * {@link AudioTrack#ENCAPSULATION_METADATA_TYPE_FRAMEWORK_TUNER},
+ * {@link AudioTrack#ENCAPSULATION_METADATA_TYPE_DVB_AD_DESCRIPTOR}.
+ *
+ * @return An array of supported encapsulation metadata types for the device. This
+ * may be an empty array if no metadata types are supported.
+ */
+ public @NonNull int[] getEncapsulationMetadataTypes() {
+ // Implement a getter in r-dev or r-tv-dev as needed.
+ return new int[0]; // be careful of returning a copy of any internal data.
+ }
+
/**
* @return The device type identifier of the audio device (i.e. TYPE_BUILTIN_SPEAKER).
*/
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8ad5c04a1f85..861b76d2b153 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4567,6 +4567,70 @@ public class AudioManager {
}
/**
+ * @hide
+ * Sets an additional audio output device delay in milliseconds.
+ *
+ * The additional output delay is a request to the output device to
+ * delay audio presentation (generally with respect to video presentation for better
+ * synchronization).
+ * It may not be supported by all output devices,
+ * and typically increases the audio latency by the amount of additional
+ * audio delay requested.
+ *
+ * If additional audio delay is supported by an audio output device,
+ * it is expected to be supported for all output streams (and configurations)
+ * opened on that device.
+ *
+ * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
+ * @param delayMs delay in milliseconds desired. This should be in range of {@code 0}
+ * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
+ * @return true if successful, false if the device does not support output device delay
+ * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean setAdditionalOutputDeviceDelay(
+ @NonNull AudioDeviceInfo device, @IntRange(from = 0) int delayMs) {
+ Objects.requireNonNull(device);
+ // Implement the setter in r-dev or r-tv-dev as needed.
+ return false;
+ }
+
+ /**
+ * @hide
+ * Returns the current additional audio output device delay in milliseconds.
+ *
+ * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
+ * @return the additional output device delay. This is a non-negative number.
+ * {@code 0} is returned if unsupported.
+ */
+ @SystemApi
+ @IntRange(from = 0)
+ public int getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(device);
+ // Implement the getter in r-dev or r-tv-dev as needed.
+ return 0;
+ }
+
+ /**
+ * @hide
+ * Returns the maximum additional audio output device delay in milliseconds.
+ *
+ * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
+ * @return the maximum output device delay in milliseconds that can be set.
+ * This is a non-negative number
+ * representing the additional audio delay supported for the device.
+ * {@code 0} is returned if unsupported.
+ */
+ @SystemApi
+ @IntRange(from = 0)
+ public int getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
+ Objects.requireNonNull(device);
+ // Implement the getter in r-dev or r-tv-dev as needed.
+ return 0;
+ }
+
+ /**
* Returns the estimated latency for the given stream type in milliseconds.
*
* DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 453704eea398..65f2f1789491 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -102,6 +102,12 @@ public final class AudioPlaybackCaptureConfiguration {
criterion -> criterion.getIntProp());
}
+ /** @return the userId's passed to {@link Builder#addMatchingUserId(int)}. */
+ public @NonNull int[] getMatchingUserIds() {
+ return getIntPredicates(AudioMixingRule.RULE_MATCH_USERID,
+ criterion -> criterion.getIntProp());
+ }
+
/** @return the usages passed to {@link Builder#excludeUsage(int)}. */
@AttributeUsage
public @NonNull int[] getExcludeUsages() {
@@ -115,6 +121,12 @@ public final class AudioPlaybackCaptureConfiguration {
criterion -> criterion.getIntProp());
}
+ /** @return the userId's passed to {@link Builder#excludeUserId(int)}. */
+ public @NonNull int[] getExcludeUserIds() {
+ return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_USERID,
+ criterion -> criterion.getIntProp());
+ }
+
private int[] getIntPredicates(int rule,
ToIntFunction<AudioMixMatchCriterion> getPredicate) {
return mAudioMixingRule.getCriteria().stream()
@@ -153,6 +165,7 @@ public final class AudioPlaybackCaptureConfiguration {
private final MediaProjection mProjection;
private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED;
private int mUidMatchType = MATCH_TYPE_UNSPECIFIED;
+ private int mUserIdMatchType = MATCH_TYPE_UNSPECIFIED;
/** @param projection A MediaProjection that supports audio projection. */
public Builder(@NonNull MediaProjection projection) {
@@ -202,6 +215,23 @@ public final class AudioPlaybackCaptureConfiguration {
}
/**
+ * Only capture audio output by app with the matching {@code userId}.
+ *
+ * <p>If called multiple times, will capture audio output by apps whose userId is any of the
+ * given userId's.
+ *
+ * @throws IllegalStateException if called in conjunction with {@link #excludeUserId(int)}.
+ */
+ public @NonNull Builder addMatchingUserId(int userId) {
+ Preconditions.checkState(
+ mUserIdMatchType != MATCH_TYPE_EXCLUSIVE,
+ ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_USERID, userId);
+ mUserIdMatchType = MATCH_TYPE_INCLUSIVE;
+ return this;
+ }
+
+ /**
* Only capture audio output that does not match the given {@link AudioAttributes}.
*
* <p>If called multiple times, will capture audio output that does not match any of the
@@ -238,6 +268,24 @@ public final class AudioPlaybackCaptureConfiguration {
}
/**
+ * Only capture audio output by apps that do not have the matching {@code userId}.
+ *
+ * <p>If called multiple times, will capture audio output by apps whose userId is not any of
+ * the given userId's.
+ *
+ * @throws IllegalStateException if called in conjunction with
+ * {@link #addMatchingUserId(int)}.
+ */
+ public @NonNull Builder excludeUserId(int userId) {
+ Preconditions.checkState(
+ mUserIdMatchType != MATCH_TYPE_INCLUSIVE,
+ ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_USERID, userId);
+ mUserIdMatchType = MATCH_TYPE_EXCLUSIVE;
+ return this;
+ }
+
+ /**
* Builds the configuration instance.
*
* @throws UnsupportedOperationException if the parameters set are incompatible.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 48d27faa0855..02cb8aafea0c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1169,6 +1169,13 @@ public class AudioSystem
/** see AudioPolicy.removeUidDeviceAffinities() */
public static native int removeUidDeviceAffinities(int uid);
+ /** see AudioPolicy.setUserIdDeviceAffinities() */
+ public static native int setUserIdDeviceAffinities(int userId, @NonNull int[] types,
+ @NonNull String[] addresses);
+
+ /** see AudioPolicy.removeUserIdDeviceAffinities() */
+ public static native int removeUserIdDeviceAffinities(int userId);
+
public static native int systemReady();
public static native float getStreamVolumeDB(int stream, int index, int device);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1f6159104d58..81275f6891ab 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -256,6 +256,38 @@ public class AudioTrack extends PlayerBase
*/
public static final int ENCAPSULATION_MODE_HANDLE = 2;
+ /* Enumeration of metadata types permitted for use by
+ * encapsulation mode audio streams.
+ */
+ /** @hide */
+ @IntDef(prefix = { "ENCAPSULATION_METADATA_TYPE_" }, value = {
+ ENCAPSULATION_METADATA_TYPE_NONE, /* reserved */
+ ENCAPSULATION_METADATA_TYPE_FRAMEWORK_TUNER,
+ ENCAPSULATION_METADATA_TYPE_DVB_AD_DESCRIPTOR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncapsulationMetadataType {}
+
+ /**
+ * Reserved do not use.
+ * @hide
+ */
+ public static final int ENCAPSULATION_METADATA_TYPE_NONE = 0; // reserved
+
+ /**
+ * Encapsulation metadata type for framework tuner information.
+ *
+ * TODO(b/147778408) Link: Fill in Tuner API info.
+ */
+ public static final int ENCAPSULATION_METADATA_TYPE_FRAMEWORK_TUNER = 1;
+
+ /**
+ * Encapsulation metadata type for DVB AD descriptor.
+ *
+ * This metadata is formatted per ETSI TS 101 154 Table E.1: AD_descriptor.
+ */
+ public static final int ENCAPSULATION_METADATA_TYPE_DVB_AD_DESCRIPTOR = 2;
+
/* Dual Mono handling is used when a stereo audio stream
* contains separate audio content on the left and right channels.
* Such information about the content of the stream may be found, for example, in
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7f1c69218f45..1f97be5c3f4d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -266,6 +266,10 @@ interface IAudioService {
int removeUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid);
+ int setUserIdDeviceAffinity(in IAudioPolicyCallback pcb, in int userId, in int[] deviceTypes,
+ in String[] deviceAddresses);
+ int removeUserIdDeviceAffinity(in IAudioPolicyCallback pcb, in int userId);
+
boolean hasHapticChannels(in Uri uri);
boolean isCallScreeningModeSupported();
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index cad5aa6aaa3c..c25a5333017b 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -356,10 +356,14 @@ public class AudioEffect {
public static final String EFFECT_AUXILIARY = "Auxiliary";
/**
* Effect connection mode is pre processing.
- * The audio pre processing effects are attached to an audio input (AudioRecord).
- * @hide
+ * The audio pre processing effects are attached to an audio input stream or device
*/
public static final String EFFECT_PRE_PROCESSING = "Pre Processing";
+ /**
+ * Effect connection mode is post processing.
+ * The audio post processing effects are attached to an audio output stream or device
+ */
+ public static final String EFFECT_POST_PROCESSING = "Post Processing";
// --------------------------------------------------------------------------
// Member variables
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 8c204d222cd4..bca3fa7834b4 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -73,6 +73,12 @@ public class AudioMixingRule {
* parameter is an instance of {@link java.lang.Integer}.
*/
public static final int RULE_MATCH_UID = 0x1 << 2;
+ /**
+ * A rule requiring the userId of the audio stream to match that specified.
+ * This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
+ * parameter is an instance of {@link java.lang.Integer}.
+ */
+ public static final int RULE_MATCH_USERID = 0x1 << 3;
private final static int RULE_EXCLUSION_MASK = 0x8000;
/**
@@ -94,6 +100,13 @@ public class AudioMixingRule {
public static final int RULE_EXCLUDE_UID =
RULE_EXCLUSION_MASK | RULE_MATCH_UID;
+ /**
+ * @hide
+ * A rule requiring the userId information to differ.
+ */
+ public static final int RULE_EXCLUDE_USERID =
+ RULE_EXCLUSION_MASK | RULE_MATCH_USERID;
+
/** @hide */
public static final class AudioMixMatchCriterion {
@UnsupportedAppUsage
@@ -125,19 +138,20 @@ public class AudioMixingRule {
dest.writeInt(mRule);
final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
switch (match_rule) {
- case RULE_MATCH_ATTRIBUTE_USAGE:
- dest.writeInt(mAttr.getUsage());
- break;
- case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- dest.writeInt(mAttr.getCapturePreset());
- break;
- case RULE_MATCH_UID:
- dest.writeInt(mIntProp);
- break;
- default:
- Log.e("AudioMixMatchCriterion", "Unknown match rule" + match_rule
- + " when writing to Parcel");
- dest.writeInt(-1);
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ dest.writeInt(mAttr.getUsage());
+ break;
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ dest.writeInt(mAttr.getCapturePreset());
+ break;
+ case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
+ dest.writeInt(mIntProp);
+ break;
+ default:
+ Log.e("AudioMixMatchCriterion", "Unknown match rule" + match_rule
+ + " when writing to Parcel");
+ dest.writeInt(-1);
}
}
@@ -203,6 +217,7 @@ public class AudioMixingRule {
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
return true;
default:
return false;
@@ -225,6 +240,7 @@ public class AudioMixingRule {
case RULE_MATCH_ATTRIBUTE_USAGE:
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
return true;
default:
return false;
@@ -234,11 +250,12 @@ public class AudioMixingRule {
private static boolean isPlayerRule(int rule) {
final int match_rule = rule & ~RULE_EXCLUSION_MASK;
switch (match_rule) {
- case RULE_MATCH_ATTRIBUTE_USAGE:
- case RULE_MATCH_UID:
- return true;
- default:
- return false;
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
+ return true;
+ default:
+ return false;
}
}
@@ -319,7 +336,8 @@ public class AudioMixingRule {
* property to match against.
* @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
- * {@link AudioMixingRule#RULE_MATCH_UID}.
+ * {@link AudioMixingRule#RULE_MATCH_UID} or
+ * {@link AudioMixingRule#RULE_MATCH_USERID}.
* @param property see the definition of each rule for the type to use (either an
* {@link AudioAttributes} or an {@link java.lang.Integer}).
* @return the same Builder instance.
@@ -349,7 +367,8 @@ public class AudioMixingRule {
* coming from the specified UID.
* @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
- * {@link AudioMixingRule#RULE_MATCH_UID}.
+ * {@link AudioMixingRule#RULE_MATCH_UID} or
+ * {@link AudioMixingRule#RULE_MATCH_USERID}.
* @param property see the definition of each rule for the type to use (either an
* {@link AudioAttributes} or an {@link java.lang.Integer}).
* @return the same Builder instance.
@@ -425,6 +444,8 @@ public class AudioMixingRule {
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
* {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET},
* {@link AudioMixingRule#RULE_MATCH_UID}, {@link AudioMixingRule#RULE_EXCLUDE_UID}.
+ * {@link AudioMixingRule#RULE_MATCH_USERID},
+ * {@link AudioMixingRule#RULE_EXCLUDE_USERID}.
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
@@ -495,6 +516,20 @@ public class AudioMixingRule {
}
}
break;
+ case RULE_MATCH_USERID:
+ // "userid"-based rule
+ if (criterion.mIntProp == intProp.intValue()) {
+ if (criterion.mRule == rule) {
+ // rule already exists, we're done
+ return this;
+ } else {
+ // criterion already exists with a another rule,
+ // it is incompatible
+ throw new IllegalArgumentException("Contradictory rule exists"
+ + " for userId " + intProp);
+ }
+ }
+ break;
}
}
// rule didn't exist, add it
@@ -504,6 +539,7 @@ public class AudioMixingRule {
mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
break;
case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
break;
default:
@@ -530,6 +566,7 @@ public class AudioMixingRule {
.setInternalCapturePreset(preset).build();
break;
case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
intProp = new Integer(in.readInt());
break;
default:
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 27f02fe528f3..32a4a4f70192 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -51,6 +51,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* @hide
@@ -404,7 +405,7 @@ public class AudioPolicy {
/**
* @hide
- * Configures the audio framework so that all audio stream originating from the given UID
+ * Configures the audio framework so that all audio streams originating from the given UID
* can only come from a set of audio devices.
* For this routing to be operational, a number of {@link AudioMix} instances must have been
* previously registered on this policy, and routed to a super-set of the given audio devices
@@ -476,6 +477,78 @@ public class AudioPolicy {
}
}
+ /**
+ * @hide
+ * Removes audio device affinity previously set by
+ * {@link #setUserIdDeviceAffinity(int, java.util.List)}.
+ * @param userId userId of the application affected.
+ * @return true if the change was successful, false otherwise.
+ */
+ @TestApi
+ @SystemApi
+ public boolean removeUserIdDeviceAffinity(int userId) {
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+ }
+ final IAudioService service = getService();
+ try {
+ final int status = service.removeUserIdDeviceAffinity(this.cb(), userId);
+ return (status == AudioManager.SUCCESS);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in removeUserIdDeviceAffinity", e);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Configures the audio framework so that all audio streams originating from the given user
+ * can only come from a set of audio devices.
+ * For this routing to be operational, a number of {@link AudioMix} instances must have been
+ * previously registered on this policy, and routed to a super-set of the given audio devices
+ * with {@link AudioMix.Builder#setDevice(android.media.AudioDeviceInfo)}. Note that having
+ * multiple devices in the list doesn't imply the signals will be duplicated on the different
+ * audio devices, final routing will depend on the {@link AudioAttributes} of the sounds being
+ * played.
+ * @param userId Android user id to affect.
+ * @param devices list of devices to which the audio stream of the application may be routed.
+ * @return true if the change was successful, false otherwise.
+ */
+ @TestApi
+ @SystemApi
+ public boolean setUserIdDeviceAffinity(int userId, @NonNull List<AudioDeviceInfo> devices) {
+ Objects.requireNonNull(devices, "Illegal null list of audio devices");
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+ }
+ final int[] deviceTypes = new int[devices.size()];
+ final String[] deviceAddresses = new String[devices.size()];
+ int i = 0;
+ for (AudioDeviceInfo device : devices) {
+ if (device == null) {
+ throw new IllegalArgumentException(
+ "Illegal null AudioDeviceInfo in setUserIdDeviceAffinity");
+ }
+ deviceTypes[i] =
+ AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
+ deviceAddresses[i] = device.getAddress();
+ i++;
+ }
+ final IAudioService service = getService();
+ try {
+ final int status = service.setUserIdDeviceAffinity(this.cb(),
+ userId, deviceTypes, deviceAddresses);
+ return (status == AudioManager.SUCCESS);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setUserIdDeviceAffinity", e);
+ return false;
+ }
+ }
+ }
+
public void setRegistration(String regId) {
synchronized (mLock) {
mRegistrationId = regId;
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index c4ba0c1fc835..b048158c3979 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -197,6 +197,14 @@ public class AudioPolicyConfig implements Parcelable {
textDump += " exclude UID ";
textDump += criterion.mIntProp;
break;
+ case AudioMixingRule.RULE_MATCH_USERID:
+ textDump += " match userId ";
+ textDump += criterion.mIntProp;
+ break;
+ case AudioMixingRule.RULE_EXCLUDE_USERID:
+ textDump += " exclude userId ";
+ textDump += criterion.mIntProp;
+ break;
default:
textDump += "invalid rule!";
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 9953626f0a7a..870c1b4a3558 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -146,6 +146,8 @@ public final class MediaSession {
* the system but will not be published until {@link #setActive(boolean)
* setActive(true)} is called. You must call {@link #release()} when
* finished with the session.
+ * <p>
+ * Note that {@link RuntimeException} will be thrown if an app creates too many sessions.
*
* @param context The context to use to create the session.
* @param tag A short name for debugging purposes.
@@ -163,6 +165,8 @@ public final class MediaSession {
* The {@code sessionInfo} can include additional unchanging information about this session.
* For example, it can include the version of the application, or the list of the custom
* commands that this session supports.
+ * <p>
+ * Note that {@link RuntimeException} will be thrown if an app creates too many sessions.
*
* @param context The context to use to create the session.
* @param tag A short name for debugging purposes.
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 9e671b1177cd..5babb1698c85 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -17,7 +17,6 @@
package android.media.tv;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.text.TextUtils;
import com.android.internal.util.Preconditions;
@@ -725,16 +724,16 @@ import java.util.Objects;
* <td>NZ_TV_G</td>
* <td>Programmes which exclude material likely to be unsuitable for children. Programmes
* may not necessarily be designed for child viewers but should not contain material likely
- * to alarm or distress them.</td>
+ * to alarm or distress them</td>
* </tr>
* <tr>
* <td>NZ_TV_PGR</td>
* <td>Programmes containing material more suited for mature audiences but not necessarily
- * unsuitable for child viewers when subject to the guidance of a parent or an adult.</td>
+ * unsuitable for child viewers when subject to the guidance of a parent or an adult</td>
* </tr>
* <tr>
* <td>NZ_TV_AO</td>
- * <td>Programmes containing adult themes and directed primarily at mature audiences.</td>
+ * <td>Programmes containing adult themes and directed primarily at mature audiences</td>
* </tr>
* <tr>
* <td valign="top" rowspan="6">SG_TV</td>
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 5e0b1eab4393..b40d43a8e616 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -353,8 +353,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)) {
+ || mEncrypted != obj.mEncrypted) {
return false;
}
@@ -382,7 +381,16 @@ public final class TvTrackInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hashCode(mId);
+ int result = Objects.hash(mId, mType, mLanguage, mDescription);
+
+ if (mType == TYPE_AUDIO) {
+ result = Objects.hash(result, mAudioChannelCount, mAudioSampleRate);
+ } else if (mType == TYPE_VIDEO) {
+ result = Objects.hash(result, mVideoWidth, mVideoHeight, mVideoFrameRate,
+ mVideoPixelAspectRatio);
+ }
+
+ return result;
}
public static final @android.annotation.NonNull Parcelable.Creator<TvTrackInfo> CREATOR =
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 97a2b22e5030..b6bd86befd87 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -124,15 +124,16 @@ public class MediaEvent extends FilterEvent{
}
/**
- * Reserves the ID which is used by HAL to provide additional information for AV data.
+ * Gets the audio handle.
*
- * <p>The corresponding data is used and released by {@link android.media.AudioTrack}.
- * <p>The data is also released when the {@link Filter} instance is closed.
+ * <p>Client gets audio handle from {@link MediaEvent}, and queues it to
+ * {@link android.media.AudioTrack} in
+ * {@link android.media.AudioTrack#ENCAPSULATION_MODE_HANDLE} format.
*
- * @return the reserved AV data ID.
- * @hide
+ * @return the audio handle.
+ * @see android.media.AudioTrack#ENCAPSULATION_MODE_HANDLE
*/
- public long reserveAvDataId() {
+ public long getAudioHandle() {
// TODO: implement
return mDataId;
}
diff --git a/media/java/android/media/voice/KeyphraseModelManager.java b/media/java/android/media/voice/KeyphraseModelManager.java
new file mode 100644
index 000000000000..3fa38e0a5854
--- /dev/null
+++ b/media/java/android/media/voice/KeyphraseModelManager.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.voice;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.util.Slog;
+
+import com.android.internal.app.IVoiceInteractionManagerService;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * This class provides management of voice based sound recognition models. Usage of this class is
+ * restricted to system or signature applications only. This allows OEMs to write apps that can
+ * manage voice based sound trigger models.
+ * Callers of this class are expected to have whitelist manifest permission MANAGE_VOICE_KEYPHRASES.
+ * Callers of this class are expected to be the designated voice interaction service via
+ * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}.
+ * @hide
+ */
+@SystemApi
+public final class KeyphraseModelManager {
+ private static final boolean DBG = false;
+ private static final String TAG = "KeyphraseModelManager";
+
+ private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
+ /**
+ * @hide
+ */
+ public KeyphraseModelManager(
+ IVoiceInteractionManagerService voiceInteractionManagerService) {
+ if (DBG) {
+ Slog.i(TAG, "KeyphraseModelManager created.");
+ }
+ mVoiceInteractionManagerService = voiceInteractionManagerService;
+ }
+
+
+ /**
+ * Gets the registered sound model for keyphrase detection for the current user.
+ * The keyphraseId and locale passed must match a supported model passed in via
+ * {@link #updateKeyphraseSoundModel}.
+ * If the active voice interaction service changes from the current user, all requests will be
+ * rejected, and any registered models will be unregistered.
+ *
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param locale The locale language tag supported by the desired model.
+ * @return Registered keyphrase sound model matching the keyphrase ID and locale. May be null if
+ * no matching sound model exists.
+ * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission
+ * or if the caller is not the active voice interaction service.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+ @Nullable
+ public SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId,
+ @NonNull Locale locale) {
+ Objects.requireNonNull(locale);
+ try {
+ return mVoiceInteractionManagerService.getKeyphraseSoundModel(keyphraseId,
+ locale.toLanguageTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Add or update the given keyphrase sound model to the registered models pool for the current
+ * user.
+ * If a model exists with the same Keyphrase ID, locale, and user list. The registered model
+ * will be overwritten with the new model.
+ * If the active voice interaction service changes from the current user, all requests will be
+ * rejected, and any registered models will be unregistered.
+ *
+ * @param model Keyphrase sound model to be updated.
+ * @throws ServiceSpecificException Thrown with error code if failed to update the keyphrase
+ * sound model.
+ * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission
+ * or if the caller is not the active voice interaction service.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+ public void updateKeyphraseSoundModel(@NonNull SoundTrigger.KeyphraseSoundModel model) {
+ Objects.requireNonNull(model);
+ try {
+ int status = mVoiceInteractionManagerService.updateKeyphraseSoundModel(model);
+ if (status != SoundTrigger.STATUS_OK) {
+ throw new ServiceSpecificException(status);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Delete keyphrase sound model from the registered models pool for the current user matching\
+ * the keyphrase ID and locale.
+ * The keyphraseId and locale passed must match a supported model passed in via
+ * {@link #updateKeyphraseSoundModel}.
+ * If the active voice interaction service changes from the current user, all requests will be
+ * rejected, and any registered models will be unregistered.
+ *
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param locale The locale language tag supported by the desired model.
+ * @throws ServiceSpecificException Thrown with error code if failed to delete the keyphrase
+ * sound model.
+ * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission
+ * or if the caller is not the active voice interaction service.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
+ public void deleteKeyphraseSoundModel(int keyphraseId, @NonNull Locale locale) {
+ Objects.requireNonNull(locale);
+ try {
+ int status = mVoiceInteractionManagerService.deleteKeyphraseSoundModel(keyphraseId,
+ locale.toLanguageTag());
+ if (status != SoundTrigger.STATUS_OK) {
+ throw new ServiceSpecificException(status);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index f979fddd7bda..c529952843a1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -311,6 +311,12 @@ public class CameraBinderTest extends AndroidTestCase {
cameraId, status));
}
@Override
+ public void onPhysicalCameraStatusChanged(int status, String cameraId,
+ String physicalCameraId) throws RemoteException {
+ Log.v(TAG, String.format("Camera %s : %s has status changed to 0x%x",
+ cameraId, physicalCameraId, status));
+ }
+ @Override
public void onCameraAccessPrioritiesChanged() {
Log.v(TAG, "Camera access permission change");
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 203adfc749d2..97b861b390ad 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -240,6 +240,7 @@ LIBANDROID {
ASurfaceTransaction_setColor; # introduced=29
ASurfaceTransaction_setDamageRegion; # introduced=29
ASurfaceTransaction_setDesiredPresentTime; # introduced=29
+ ASurfaceTransaction_setFrameRate; # introduced=30
ASurfaceTransaction_setGeometry; # introduced=29
ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29
ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index b34b31ac8439..392c9f6404ba 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -545,3 +545,18 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
transaction->setBackgroundColor(surfaceControl, color, alpha, static_cast<ui::Dataspace>(dataspace));
}
+
+void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl, float frameRate) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ if (frameRate < 0) {
+ ALOGE("Failed to set frame ate - invalid frame rate");
+ return;
+ }
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+ transaction->setFrameRate(surfaceControl, frameRate);
+}
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 1c45ea6aaecc..79bcc15e1f0f 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -208,13 +208,6 @@ const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* i
return getMimeType(toDecoder(info)->mCodec->getEncodedFormat());
}
-bool AImageDecoderHeaderInfo_isAnimated(const AImageDecoderHeaderInfo* info) {
- if (!info) {
- return false;
- }
- return toDecoder(info)->mCodec->codec()->getFrameCount() > 1;
-}
-
int32_t AImageDecoderHeaderInfo_getDataSpace(const AImageDecoderHeaderInfo* info) {
if (!info) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
@@ -247,8 +240,7 @@ static AndroidBitmapFormat getFormat(SkColorType colorType) {
}
}
-AndroidBitmapFormat AImageDecoderHeaderInfo_getAndroidBitmapFormat(
- const AImageDecoderHeaderInfo* info) {
+int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(const AImageDecoderHeaderInfo* info) {
if (!info) {
return ANDROID_BITMAP_FORMAT_NONE;
}
@@ -281,7 +273,7 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* decoder, bool requir
? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
}
-int AImageDecoder_setTargetSize(AImageDecoder* decoder, int width, int height) {
+int AImageDecoder_setTargetSize(AImageDecoder* decoder, int32_t width, int32_t height) {
if (!decoder) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
@@ -291,7 +283,7 @@ int AImageDecoder_setTargetSize(AImageDecoder* decoder, int width, int height) {
}
int AImageDecoder_computeSampledSize(const AImageDecoder* decoder, int sampleSize,
- int* width, int* height) {
+ int32_t* width, int32_t* height) {
if (!decoder || !width || !height || sampleSize < 1) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index 1b396b893f4e..01c14770bebd 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -17,7 +17,6 @@ LIBJNIGRAPHICS {
AImageDecoderHeaderInfo_getHeight; # introduced=30
AImageDecoderHeaderInfo_getMimeType; # introduced=30
AImageDecoderHeaderInfo_getAlphaFlags; # introduced=30
- AImageDecoderHeaderInfo_isAnimated; # introduced=30
AImageDecoderHeaderInfo_getAndroidBitmapFormat; # introduced=30
AImageDecoderHeaderInfo_getDataSpace; # introduced=30
AndroidBitmap_getInfo;
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index f94f69f0fd3f..b4ea0a6132a5 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -16,13 +16,12 @@
package com.google.android.gles_jni;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 2a8d07f03148..3c808a6ada48 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -20,14 +20,13 @@
package com.google.android.gles_jni;
import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.nio.Buffer;
import javax.microedition.khronos.opengles.GL10;
diff --git a/packages/CarSystemUI/res/layout/super_notification_shade.xml b/packages/CarSystemUI/res/layout/super_notification_shade.xml
index 3fe1ea331a07..cb65045533f8 100644
--- a/packages/CarSystemUI/res/layout/super_notification_shade.xml
+++ b/packages/CarSystemUI/res/layout/super_notification_shade.xml
@@ -59,24 +59,6 @@
sysui:ignoreRightInset="true"
/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/status_bar_height"
- android:orientation="vertical"
- >
- <FrameLayout
- android:id="@+id/status_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- />
-
- <FrameLayout
- android:id="@+id/car_top_navigation_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </LinearLayout>
-
<include layout="@layout/brightness_mirror"/>
<ViewStub android:id="@+id/fullscreen_user_switcher_stub"
diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml
index c7b22f823ba4..d93f62f8809d 100644
--- a/packages/CarSystemUI/res/layout/super_status_bar.xml
+++ b/packages/CarSystemUI/res/layout/super_status_bar.xml
@@ -25,9 +25,22 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
- <FrameLayout
- android:id="@+id/status_bar_container"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:id="@+id/status_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ />
+
+ <FrameLayout
+ android:id="@+id/car_top_navigation_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
index c7e14d677b04..3f55ac8ccace 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/SystemUIPrimaryWindowController.java
@@ -113,7 +113,7 @@ public class SystemUIPrimaryWindowController implements
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
- mLp.setFitWindowInsetsTypes(/* types= */ 0);
+ mLp.setFitInsetsTypes(/* types= */ 0);
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("SystemUIPrimaryWindow");
mLp.packageName = mContext.getPackageName();
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 78764dd19741..3a5201517af2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -235,7 +235,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
private void buildNavBarWindows() {
mTopNavigationBarWindow = mSuperStatusBarViewFactory
- .getNotificationShadeWindowView()
+ .getStatusBarWindowView()
.findViewById(R.id.car_top_navigation_bar_container);
mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
@@ -296,7 +296,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
leftlp.windowAnimations = 0;
leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
leftlp.gravity = Gravity.LEFT;
- leftlp.setFitWindowInsetsTypes(0 /* types */);
+ leftlp.setFitInsetsTypes(0 /* types */);
mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
}
if (mRightNavigationBarWindow != null) {
@@ -314,7 +314,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
rightlp.windowAnimations = 0;
rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
rightlp.gravity = Gravity.RIGHT;
- rightlp.setFitWindowInsetsTypes(0 /* types */);
+ rightlp.setFitInsetsTypes(0 /* types */);
mWindowManager.addView(mRightNavigationBarWindow, rightlp);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
index b2f8aad77dd4..07dbd667acf4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java
@@ -249,7 +249,7 @@ class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
PixelFormat.TRANSLUCENT
);
- attrs.setFitWindowInsetsTypes(0 /* types */);
+ attrs.setFitInsetsTypes(0 /* types */);
return attrs;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 8c756ecbaefc..7dd3be4b2c11 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -20,6 +20,7 @@ import static android.content.DialogInterface.BUTTON_NEGATIVE;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.os.UserManager.DISALLOW_ADD_USER;
import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
+import static android.view.WindowInsets.Type.statusBars;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -367,8 +368,8 @@ public class UserGridRecyclerView extends RecyclerView {
window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- window.setFitWindowInsetsTypes(
- window.getFitWindowInsetsTypes() & ~WindowInsets.Type.statusBars());
+ window.getAttributes().setFitInsetsTypes(
+ window.getAttributes().getFitInsetsTypes() & ~statusBars());
}
private void notifyUserSelected(UserRecord userRecord) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index 2d7d59cc0022..4ebb1029ff04 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -199,8 +199,7 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt
return;
}
if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
- && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)
- && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE_TRANSITION)) {
+ && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)) {
mFrictionSld.setState(STATE_SECURED);
} else if (mWifiEntry.isMetered()) {
mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c913999ecb7c..486386f3d284 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -62,6 +62,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
@@ -275,6 +276,9 @@ public class SettingsProvider extends ContentProvider {
private final Object mLock = new Object();
@GuardedBy("mLock")
+ private RemoteCallback mConfigMonitorCallback;
+
+ @GuardedBy("mLock")
private SettingsRegistry mSettingsRegistry;
@GuardedBy("mLock")
@@ -450,8 +454,17 @@ public class SettingsProvider extends ContentProvider {
case Settings.CALL_METHOD_LIST_CONFIG: {
String prefix = getSettingPrefix(args);
- return packageValuesForCallResult(getAllConfigFlags(prefix),
+ Bundle result = packageValuesForCallResult(getAllConfigFlags(prefix),
isTrackingGeneration(args));
+ reportDeviceConfigAccess(prefix);
+ return result;
+ }
+
+ case Settings.CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG: {
+ RemoteCallback callback = args.getParcelable(
+ Settings.CALL_METHOD_MONITOR_CALLBACK_KEY);
+ setMonitorCallback(callback);
+ break;
}
case Settings.CALL_METHOD_LIST_GLOBAL: {
@@ -1052,8 +1065,9 @@ public class SettingsProvider extends ContentProvider {
enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
synchronized (mLock) {
- return mSettingsRegistry.setSettingsLocked(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM,
- prefix, keyValues, resolveCallingPackage());
+ final int key = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+ return mSettingsRegistry.setConfigSettingsLocked(key, prefix, keyValues,
+ resolveCallingPackage());
}
}
@@ -2155,6 +2169,59 @@ public class SettingsProvider extends ContentProvider {
return result;
}
+ private void setMonitorCallback(RemoteCallback callback) {
+ if (callback == null) {
+ return;
+ }
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS,
+ "Permission denial: registering for config access requires: "
+ + Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS);
+ synchronized (mLock) {
+ mConfigMonitorCallback = callback;
+ }
+ }
+
+ private void reportDeviceConfigAccess(@Nullable String prefix) {
+ if (prefix == null) {
+ return;
+ }
+ String callingPackage = getCallingPackage();
+ String namespace = prefix.replace("/", "");
+ if (DeviceConfig.getPublicNamespaces().contains(namespace)) {
+ return;
+ }
+ synchronized (mLock) {
+ if (mConfigMonitorCallback != null) {
+ Bundle callbackResult = new Bundle();
+ callbackResult.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE,
+ Settings.EXTRA_ACCESS_CALLBACK);
+ callbackResult.putString(Settings.EXTRA_CALLING_PACKAGE, callingPackage);
+ callbackResult.putString(Settings.EXTRA_NAMESPACE, namespace);
+ mConfigMonitorCallback.sendResult(callbackResult);
+ }
+ }
+ }
+
+ private void reportDeviceConfigUpdate(@Nullable String prefix) {
+ if (prefix == null) {
+ return;
+ }
+ String namespace = prefix.replace("/", "");
+ if (DeviceConfig.getPublicNamespaces().contains(namespace)) {
+ return;
+ }
+ synchronized (mLock) {
+ if (mConfigMonitorCallback != null) {
+ Bundle callbackResult = new Bundle();
+ callbackResult.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE,
+ Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK);
+ callbackResult.putString(Settings.EXTRA_NAMESPACE, namespace);
+ mConfigMonitorCallback.sendResult(callbackResult);
+ }
+ }
+ }
+
private static int getRequestingUserId(Bundle args) {
final int callingUserId = UserHandle.getCallingUserId();
return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
@@ -2715,22 +2782,20 @@ public class SettingsProvider extends ContentProvider {
}
/**
- * Set Settings using consumed keyValues, returns true if the keyValues can be set, false
- * otherwise.
+ * Set Config Settings using consumed keyValues, returns true if the keyValues can be set,
+ * false otherwise.
*/
- public boolean setSettingsLocked(int type, int userId, String prefix,
+ public boolean setConfigSettingsLocked(int key, String prefix,
Map<String, String> keyValues, String packageName) {
- final int key = makeKey(type, userId);
-
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState != null) {
- if (SETTINGS_TYPE_CONFIG == type && settingsState.isNewConfigBannedLocked(prefix,
- keyValues)) {
+ if (settingsState.isNewConfigBannedLocked(prefix, keyValues)) {
return false;
}
List<String> changedSettings =
settingsState.setSettingsLocked(prefix, keyValues, packageName);
if (!changedSettings.isEmpty()) {
+ reportDeviceConfigUpdate(prefix);
notifyForConfigSettingsChangeLocked(key, prefix, changedSettings);
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 1cabee1ae679..2d288ff40b2c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,12 +16,15 @@
package com.android.systemui.shared.recents;
+import android.graphics.Bitmap;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
/**
* Temporary callbacks into SystemUI.
+ * Next id = 22
*/
interface ISystemUiProxy {
@@ -114,4 +117,10 @@ interface ISystemUiProxy {
* Sets the shelf height and visibility.
*/
void setShelfHeight(boolean visible, int shelfHeight) = 20;
+
+ /**
+ * Handle the provided image as if it was a screenshot.
+ */
+ void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
+ in Insets visibleInsets, int taskId) = 21;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
index 70a464dd254c..871cae3b4f8d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/UniversalSmartspaceUtils.java
@@ -37,7 +37,7 @@ public final class UniversalSmartspaceUtils {
Intent intent = new Intent(ACTION_REQUEST_SMARTSPACE_VIEW);
Bundle inputBundle = new Bundle();
- inputBundle.putBinder(BUNDLE_KEY_INPUT_TOKEN, surfaceView.getInputToken());
+ inputBundle.putBinder(BUNDLE_KEY_INPUT_TOKEN, surfaceView.getHostToken());
return intent
.putExtra(INTENT_KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl())
.putExtra(INTENT_KEY_INPUT_BUNDLE, inputBundle)
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index 2f8ef2dc8828..b2423b9bf252 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -172,7 +172,7 @@ public class AdminSecondaryLockScreenController {
private void onSurfaceReady() {
try {
- mClient.onSurfaceReady(mView.getInputToken(), mCallback);
+ mClient.onSurfaceReady(mView.getHostToken(), mCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error in onSurfaceReady", e);
dismiss(KeyguardUpdateMonitor.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 4a5bc2a8e28e..0106609b9271 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -39,7 +39,6 @@ import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -337,15 +336,15 @@ public class CarrierTextController {
CharSequence text =
getContext().getText(com.android.internal.R.string.emergency_calls_only);
Intent i = getContext().registerReceiver(null,
- new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
+ new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED));
if (i != null) {
String spn = "";
String plmn = "";
- if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
- spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
+ if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) {
+ spn = i.getStringExtra(TelephonyManager.EXTRA_SPN);
}
- if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
- plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+ if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) {
+ plmn = i.getStringExtra(TelephonyManager.EXTRA_PLMN);
}
if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
if (Objects.equals(plmn, spn)) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 4e7956db4a2b..571c4ae0e386 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -290,7 +290,7 @@ public class KeyguardDisplayManager {
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- getWindow().setFitWindowInsetsTypes(0 /* types */);
+ getWindow().getAttributes().setFitInsetsTypes(0 /* types */);
getWindow().setNavigationBarContrastEnforced(false);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f51cd83bb2d1..58a6c17e8239 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -92,7 +92,6 @@ import android.util.Log;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.DejankUtils;
@@ -1083,7 +1082,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health,
maxChargingMicroWatt));
mHandler.sendMessage(msg);
- } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+ } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
SimData args = SimData.fromIntent(intent);
// ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
// keep compatibility with apps that aren't direct boot aware.
@@ -1122,7 +1121,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
mHandler.sendMessage(
mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
- } else if (TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
+ } else if (TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
} else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
action)) {
@@ -1273,7 +1272,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
static SimData fromIntent(Intent intent) {
int state;
- if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
+ if (!Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
}
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
@@ -1673,7 +1672,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(Intent.ACTION_SERVICE_STATE);
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index db8b5831faf1..e66b9f21bd8c 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -503,7 +503,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
lp.gravity = Gravity.TOP | Gravity.LEFT;
}
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- lp.setFitWindowInsetsTypes(0 /* types */);
+ lp.setFitInsetsTypes(0 /* types */);
if (isLandscape(mRotation)) {
lp.width = WRAP_CONTENT;
lp.height = MATCH_PARENT;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index 659629b59b45..5532a0427e79 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -70,7 +70,7 @@ public class AssistDisclosure {
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
PixelFormat.TRANSLUCENT);
lp.setTitle("AssistDisclosure");
- lp.setFitWindowInsetsTypes(0 /* types */);
+ lp.setFitInsetsTypes(0 /* types */);
mWm.addView(mView, lp);
mViewAdded = true;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index eb615a0392fa..f201a6fb1137 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -85,7 +85,7 @@ public class DefaultUiController implements AssistManager.UiController {
PixelFormat.TRANSLUCENT);
mLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
mLayoutParams.gravity = Gravity.BOTTOM;
- mLayoutParams.setFitWindowInsetsTypes(0 /* types */);
+ mLayoutParams.setFitInsetsTypes(0 /* types */);
mLayoutParams.setTitle("Assist");
mInvocationLightsView = (InvocationLightsView)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 89446adb0fd7..b8d32aec30e3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -592,7 +592,7 @@ public class AuthContainerView extends LinearLayout
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("BiometricPrompt");
lp.token = windowToken;
- lp.setFitWindowInsetsTypes(lp.getFitWindowInsetsTypes() & ~Type.statusBars());
+ lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~Type.statusBars());
return lp;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
index ccfd3a57811c..82c8a469a057 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java
@@ -72,10 +72,10 @@ public class AuthCredentialPasswordView extends AuthCredentialView
}
// Wait a bit to focus the field so the focusable flag on the window is already set then.
- post(() -> {
+ postDelayed(() -> {
mPasswordField.requestFocus();
mImm.showSoftInput(mPasswordField, InputMethodManager.SHOW_IMPLICIT);
- });
+ }, 100);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index e7055847f034..6e23777babd9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -157,6 +157,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
PackageManager pm = c.getPackageManager();
ApplicationInfo appInfo;
Drawable badgedIcon;
+ Drawable appIcon;
try {
appInfo = pm.getApplicationInfo(
packageName,
@@ -167,7 +168,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
if (appInfo != null) {
info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
}
- Drawable appIcon = pm.getApplicationIcon(packageName);
+ appIcon = pm.getApplicationIcon(packageName);
badgedIcon = pm.getUserBadgedIcon(appIcon, sbn.getUser());
} catch (PackageManager.NameNotFoundException exception) {
// If we can't find package... don't think we should show the bubble.
@@ -178,6 +179,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
// Badged bubble image
Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
b.getEntry().getBubbleMetadata());
+ if (bubbleDrawable == null) {
+ // Default to app icon
+ bubbleDrawable = appIcon;
+ }
+
BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon);
info.badgedBubbleImage = iconFactory.getBubbleBitmap(bubbleDrawable,
badgeBitmapInfo).icon;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 37351985b3bd..83f6d45465b3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1577,7 +1577,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- window.setFitWindowInsetsTypes(0 /* types */);
+ window.getAttributes().setFitInsetsTypes(0 /* types */);
setTitle(R.string.global_actions);
mPanelController = plugin;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index c911bf28effd..dd1856a93d2e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -126,7 +126,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- window.setFitWindowInsetsTypes(0 /* types */);
+ window.getAttributes().setFitInsetsTypes(0 /* types */);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
index 750cc607abe3..b7258117c48c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java
@@ -109,7 +109,7 @@ public class PipDismissViewController {
lp.setTitle("pip-dismiss-overlay");
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.setFitWindowInsetsTypes(0 /* types */);
+ lp.setFitInsetsTypes(0 /* types */);
mWindowManager.addView(mDismissView, lp);
}
mDismissView.animate().cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 569f660d1797..79a33c926993 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -38,6 +38,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
@@ -55,6 +57,7 @@ import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.Dumpable;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipUI;
@@ -115,6 +118,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private final DeviceProvisionedController mDeviceProvisionedController;
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
+ private final ScreenshotHelper mScreenshotHelper;
private Region mActiveNavBarRegion;
@@ -365,6 +369,13 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
+ @Override
+ public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
+ Insets visibleInsets, int taskId) {
+ mScreenshotHelper.provideScreenshot(screenImage, locationInScreen, visibleInsets,
+ taskId, mHandler, null);
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -518,6 +529,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Listen for status bar state changes
statusBarWinController.registerCallback(mStatusBarWindowCallback);
+ mScreenshotHelper = new ScreenshotHelper(context);
}
public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 1d649eee4d57..fe84d81836e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -138,7 +138,7 @@ public class ScreenPinningRequest implements View.OnClickListener,
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("ScreenPinningConfirmation");
lp.gravity = Gravity.FILL;
- lp.setFitWindowInsetsTypes(0 /* types */);
+ lp.setFitInsetsTypes(0 /* types */);
return lp;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 50e9a51478ed..880b8f8776e8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -29,6 +29,7 @@ import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.Notification;
@@ -38,6 +39,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PointF;
@@ -240,7 +242,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
PixelFormat.TRANSLUCENT);
mWindowLayoutParams.setTitle("ScreenshotAnimation");
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mWindowLayoutParams.setFitWindowInsetsTypes(0 /* types */);
+ mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
@@ -300,8 +302,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
int width = crop.width();
int height = crop.height();
- // Take the screenshot
- mScreenBitmap = SurfaceControl.screenshot(crop, width, height, rot);
+ takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, null);
+ }
+
+ private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect) {
+ mScreenBitmap = screenshot;
if (mScreenBitmap == null) {
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
@@ -317,7 +322,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
// Start the post-screenshot animation
- startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels);
+ startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
+ screenRect);
}
void takeScreenshot(Consumer<Uri> finisher) {
@@ -327,9 +333,16 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
}
+ void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
+ Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
+ // TODO use taskId and visibleInsets
+ takeScreenshot(screenshot, finisher, screenshotScreenBounds);
+ }
+
/**
* Displays a screenshot selector
*/
+ @SuppressLint("ClickableViewAccessibility")
void takeScreenshotPartial(final Consumer<Uri> finisher) {
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
@@ -402,7 +415,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
/**
* Starts the animation after taking the screenshot
*/
- private void startAnimation(final Consumer<Uri> finisher, int w, int h) {
+ private void startAnimation(final Consumer<Uri> finisher, int w, int h,
+ @Nullable Rect screenRect) {
// If power save is on, show a toast so there is some visual indication that a screenshot
// has been taken.
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -422,7 +436,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mScreenshotAnimation.removeAllListeners();
}
- ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
+ ValueAnimator screenshotDropInAnim = screenRect != null ? createRectAnimation(screenRect)
+ : createScreenshotDropInAnimation();
ValueAnimator screenshotFadeOutAnim = createScreenshotToCornerAnimation(w, h);
mScreenshotAnimation = new AnimatorSet();
mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
@@ -460,6 +475,46 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
});
}
+ private ValueAnimator createRectAnimation(Rect rect) {
+ mScreenshotView.setAdjustViewBounds(true);
+ mScreenshotView.setMaxHeight(rect.height());
+ mScreenshotView.setMaxWidth(rect.width());
+
+ final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
+ / SCREENSHOT_DROP_IN_DURATION);
+ final float flashDurationPct = 2f * flashPeakDurationPct;
+ final Interpolator scaleInterpolator = x -> {
+ // We start scaling when the flash is at it's peak
+ if (x < flashPeakDurationPct) {
+ return 0;
+ }
+ return (x - flashDurationPct) / (1f - flashDurationPct);
+ };
+
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mBackgroundView.setAlpha(0f);
+ mBackgroundView.setVisibility(View.VISIBLE);
+ mScreenshotView.setAlpha(0f);
+ mScreenshotView.setElevation(0f);
+ mScreenshotView.setTranslationX(0f);
+ mScreenshotView.setTranslationY(0f);
+ mScreenshotView.setScaleX(1f);
+ mScreenshotView.setScaleY(1f);
+ mScreenshotView.setVisibility(View.VISIBLE);
+ }
+ });
+ anim.addUpdateListener(animation -> {
+ float t = (Float) animation.getAnimatedValue();
+ mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
+ mScreenshotView.setAlpha(t);
+ });
+ return anim;
+ }
+
private ValueAnimator createScreenshotDropInAnimation() {
final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
/ SCREENSHOT_DROP_IN_DURATION);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
index 16447fbdd4aa..f3614ffbdb1b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
@@ -30,6 +30,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -156,7 +157,7 @@ public class GlobalScreenshotLegacy {
PixelFormat.TRANSLUCENT);
mWindowLayoutParams.setTitle("ScreenshotAnimation");
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mWindowLayoutParams.setFitWindowInsetsTypes(0 /* types */);
+ mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
@@ -205,8 +206,13 @@ public class GlobalScreenshotLegacy {
int width = crop.width();
int height = crop.height();
- // Take the screenshot
- mScreenBitmap = SurfaceControl.screenshot(crop, width, height, rot);
+ takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher,
+ statusBarVisible, navBarVisible, null);
+ }
+
+ private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, boolean statusBarVisible,
+ boolean navBarVisible, Rect screenboundsOfBitmap) {
+ mScreenBitmap = screenshot;
if (mScreenBitmap == null) {
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
@@ -220,7 +226,7 @@ public class GlobalScreenshotLegacy {
// Start the post-screenshot animation
startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
- statusBarVisible, navBarVisible);
+ statusBarVisible, navBarVisible, screenboundsOfBitmap);
}
void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible, boolean navBarVisible) {
@@ -229,6 +235,12 @@ public class GlobalScreenshotLegacy {
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
}
+ void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
+ Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
+ // TODO use taskId and visibleInsets
+ takeScreenshot(screenshot, finisher, false, false, screenshotScreenBounds);
+ }
+
/**
* Displays a screenshot selector
*/
@@ -302,7 +314,7 @@ public class GlobalScreenshotLegacy {
* Starts the animation after taking the screenshot
*/
private void startAnimation(final Consumer<Uri> finisher, int w, int h,
- boolean statusBarVisible, boolean navBarVisible) {
+ boolean statusBarVisible, boolean navBarVisible, @Nullable Rect screenBoundsOfBitmap) {
// If power save is on, show a toast so there is some visual indication that a screenshot
// has been taken.
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -323,7 +335,8 @@ public class GlobalScreenshotLegacy {
}
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
- ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
+ ValueAnimator screenshotDropInAnim = screenBoundsOfBitmap != null
+ ? createRectAnimation(screenBoundsOfBitmap) : createScreenshotDropInAnimation();
ValueAnimator screenshotFadeOutAnim =
createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible);
mScreenshotAnimation = new AnimatorSet();
@@ -430,6 +443,53 @@ public class GlobalScreenshotLegacy {
return anim;
}
+ /**
+ * If a bitmap was supplied to be used as the screenshot, animated from where that bitmap was
+ * on screen, rather than using the whole screen.
+ */
+ private ValueAnimator createRectAnimation(Rect rect) {
+ mScreenshotView.setAdjustViewBounds(true);
+ mScreenshotView.setMaxHeight(rect.height());
+ mScreenshotView.setMaxWidth(rect.width());
+
+ final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
+ / SCREENSHOT_DROP_IN_DURATION);
+ final float flashDurationPct = 2f * flashPeakDurationPct;
+ final Interpolator scaleInterpolator = x -> {
+ // We start scaling when the flash is at it's peak
+ if (x < flashPeakDurationPct) {
+ return 0;
+ }
+ return (x - flashDurationPct) / (1f - flashDurationPct);
+ };
+
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mBackgroundView.setAlpha(0f);
+ mBackgroundView.setVisibility(View.VISIBLE);
+ mScreenshotView.setAlpha(0f);
+ mScreenshotView.setElevation(0f);
+ mScreenshotView.setTranslationX(0f);
+ mScreenshotView.setTranslationY(0f);
+ mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
+ mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
+ mScreenshotView.setVisibility(View.VISIBLE);
+ }
+ });
+ anim.addUpdateListener(animation -> {
+ float t = (Float) animation.getAnimatedValue();
+ float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
+ - scaleInterpolator.getInterpolation(t)
+ * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
+ mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
+ mScreenshotView.setAlpha(t);
+ });
+ return anim;
+ }
+
private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
boolean navBarVisible) {
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 9570b5a3b57c..4ac59df07eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -22,6 +22,9 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREEN
import android.app.Service;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -85,6 +88,22 @@ public class TakeScreenshotService extends Service {
finisher, msg.arg1 > 0, msg.arg2 > 0);
}
break;
+ case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
+ Bitmap screenshot = msg.getData().getParcelable(
+ WindowManager.PARCEL_KEY_SCREENSHOT_BITMAP);
+ Rect screenBounds = msg.getData().getParcelable(
+ WindowManager.PARCEL_KEY_SCREENSHOT_BOUNDS);
+ Insets insets = msg.getData().getParcelable(
+ WindowManager.PARCEL_KEY_SCREENSHOT_INSETS);
+ int taskId = msg.getData().getInt(WindowManager.PARCEL_KEY_SCREENSHOT_TASK_ID);
+ if (useCornerFlow) {
+ mScreenshot.handleImageAsScreenshot(
+ screenshot, screenBounds, insets, taskId, finisher);
+ } else {
+ mScreenshotLegacy.handleImageAsScreenshot(
+ screenshot, screenBounds, insets, taskId, finisher);
+ }
+ break;
default:
Log.d(TAG, "Invalid screenshot option: " + msg.what);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index ac05c53c38dd..6839921e90a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -56,7 +56,7 @@ public class FeatureFlags {
}
public boolean isNewNotifPipelineEnabled() {
- return getDeviceConfigFlag("notification.newpipeline.enabled", false);
+ return getDeviceConfigFlag("notification.newpipeline.enabled", true);
}
public boolean isNewNotifPipelineRenderingEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
index da119c1502c6..854444fc8bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import android.app.Notification;
-import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
@@ -30,6 +29,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+import com.android.systemui.util.Assert;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.HashMap;
import java.util.Map;
@@ -47,6 +48,8 @@ import javax.inject.Singleton;
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceController
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender
+ *
+ * TODO: AppOps stuff should be spun off into its own coordinator
*/
@Singleton
public class ForegroundCoordinator implements Coordinator {
@@ -54,7 +57,7 @@ public class ForegroundCoordinator implements Coordinator {
private final ForegroundServiceController mForegroundServiceController;
private final AppOpsController mAppOpsController;
- private final Handler mMainHandler;
+ private final DelayableExecutor mMainExecutor;
private NotifPipeline mNotifPipeline;
@@ -62,10 +65,10 @@ public class ForegroundCoordinator implements Coordinator {
public ForegroundCoordinator(
ForegroundServiceController foregroundServiceController,
AppOpsController appOpsController,
- @Main Handler mainHandler) {
+ @Main DelayableExecutor mainExecutor) {
mForegroundServiceController = foregroundServiceController;
mAppOpsController = appOpsController;
- mMainHandler = mainHandler;
+ mMainExecutor = mainExecutor;
}
@Override
@@ -78,11 +81,11 @@ public class ForegroundCoordinator implements Coordinator {
// listen for new notifications to add appOps
mNotifPipeline.addCollectionListener(mNotifCollectionListener);
- // when appOps change, update any relevant notifications to update appOps for
- mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged);
-
// filter out foreground service notifications that aren't necessary anymore
mNotifPipeline.addPreGroupFilter(mNotifFilter);
+
+ // when appOps change, update any relevant notifications to update appOps for
+ mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged);
}
/**
@@ -93,7 +96,8 @@ public class ForegroundCoordinator implements Coordinator {
public boolean shouldFilterOut(NotificationEntry entry, long now) {
StatusBarNotification sbn = entry.getSbn();
if (mForegroundServiceController.isDisclosureNotification(sbn)
- && !mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId())) {
+ && !mForegroundServiceController.isDisclosureNeededForUser(
+ sbn.getUser().getIdentifier())) {
return true;
}
@@ -102,7 +106,7 @@ public class ForegroundCoordinator implements Coordinator {
Notification.EXTRA_FOREGROUND_APPS);
if (apps != null && apps.length >= 1) {
if (!mForegroundServiceController.isSystemAlertWarningNeeded(
- sbn.getUserId(), apps[0])) {
+ sbn.getUser().getIdentifier(), apps[0])) {
return true;
}
}
@@ -119,7 +123,7 @@ public class ForegroundCoordinator implements Coordinator {
new NotifLifetimeExtender() {
private static final int MIN_FGS_TIME_MS = 5000;
private OnEndLifetimeExtensionCallback mEndCallback;
- private Map<String, Runnable> mEndRunnables = new HashMap<>();
+ private Map<NotificationEntry, Runnable> mEndRunnables = new HashMap<>();
@Override
public String getName() {
@@ -142,16 +146,18 @@ public class ForegroundCoordinator implements Coordinator {
final boolean extendLife = currTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS;
if (extendLife) {
- if (!mEndRunnables.containsKey(entry.getKey())) {
- final Runnable runnable = new Runnable() {
- @Override
- public void run() {
- mEndCallback.onEndLifetimeExtension(mForegroundLifetimeExtender, entry);
- }
+ if (!mEndRunnables.containsKey(entry)) {
+ final Runnable endExtensionRunnable = () -> {
+ mEndRunnables.remove(entry);
+ mEndCallback.onEndLifetimeExtension(
+ mForegroundLifetimeExtender,
+ entry);
};
- mEndRunnables.put(entry.getKey(), runnable);
- mMainHandler.postDelayed(runnable,
+
+ final Runnable cancelRunnable = mMainExecutor.executeDelayed(
+ endExtensionRunnable,
MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime()));
+ mEndRunnables.put(entry, cancelRunnable);
}
}
@@ -160,9 +166,9 @@ public class ForegroundCoordinator implements Coordinator {
@Override
public void cancelLifetimeExtension(NotificationEntry entry) {
- if (mEndRunnables.containsKey(entry.getKey())) {
- Runnable endRunnable = mEndRunnables.remove(entry.getKey());
- mMainHandler.removeCallbacks(endRunnable);
+ Runnable cancelRunnable = mEndRunnables.remove(entry);
+ if (cancelRunnable != null) {
+ cancelRunnable.run();
}
}
};
@@ -184,25 +190,32 @@ public class ForegroundCoordinator implements Coordinator {
private void tagForeground(NotificationEntry entry) {
final StatusBarNotification sbn = entry.getSbn();
// note: requires that the ForegroundServiceController is updating their appOps first
- ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(sbn.getUserId(),
- sbn.getPackageName());
+ ArraySet<Integer> activeOps =
+ mForegroundServiceController.getAppOps(
+ sbn.getUser().getIdentifier(),
+ sbn.getPackageName());
if (activeOps != null) {
- synchronized (entry.mActiveAppOps) {
- entry.mActiveAppOps.clear();
- entry.mActiveAppOps.addAll(activeOps);
- }
+ entry.mActiveAppOps.clear();
+ entry.mActiveAppOps.addAll(activeOps);
}
}
};
+ private void onAppOpsChanged(int code, int uid, String packageName, boolean active) {
+ mMainExecutor.execute(() -> handleAppOpsChanged(code, uid, packageName, active));
+ }
+
/**
* Update the appOp for the posted notification associated with the current foreground service
+ *
* @param code code for appOp to add/remove
* @param uid of user the notification is sent to
* @param packageName package that created the notification
* @param active whether the appOpCode is active or not
*/
- private void onAppOpsChanged(int code, int uid, String packageName, boolean active) {
+ private void handleAppOpsChanged(int code, int uid, String packageName, boolean active) {
+ Assert.isMainThread();
+
int userId = UserHandle.getUserId(uid);
// Update appOp if there's an associated posted notification:
@@ -214,15 +227,13 @@ public class ForegroundCoordinator implements Coordinator {
&& uid == entry.getSbn().getUid()
&& packageName.equals(entry.getSbn().getPackageName())) {
boolean changed;
- synchronized (entry.mActiveAppOps) {
- if (active) {
- changed = entry.mActiveAppOps.add(code);
- } else {
- changed = entry.mActiveAppOps.remove(code);
- }
+ if (active) {
+ changed = entry.mActiveAppOps.add(code);
+ } else {
+ changed = entry.mActiveAppOps.remove(code);
}
if (changed) {
- mMainHandler.post(mNotifFilter::invalidateList);
+ mNotifFilter.invalidateList();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 315ea0a49bb7..4f27c0f04c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -35,6 +35,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
import android.view.WindowInsets.Type
+import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
import android.widget.TextView
import com.android.internal.annotations.VisibleForTesting
@@ -288,13 +289,13 @@ class ChannelEditorDialogController @Inject constructor(
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
addFlags(wmFlags)
setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL)
- setFitWindowInsetsTypes(getFitWindowInsetsTypes() and Type.statusBars().inv())
setWindowAnimations(com.android.internal.R.style.Animation_InputMethod)
attributes = attributes.apply {
format = PixelFormat.TRANSLUCENT
title = ChannelEditorDialogController::class.java.simpleName
gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv()
width = MATCH_PARENT
height = WRAP_CONTENT
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index ef581db0b053..6bd122d97dea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -304,7 +304,7 @@ public class EdgeBackGestureHandler implements DisplayListener,
layoutParams.setTitle(TAG + mContext.getDisplayId());
layoutParams.accessibilityTitle = mContext.getString(R.string.nav_bar_edge_panel);
layoutParams.windowAnimations = 0;
- layoutParams.setFitWindowInsetsTypes(0 /* types */);
+ layoutParams.setFitInsetsTypes(0 /* types */);
return layoutParams;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
index 783e7adf2a8b..16b5a2389ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java
@@ -84,7 +84,7 @@ public class FloatingRotationButton implements RotationButton {
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("FloatingRotationButton");
- lp.setFitWindowInsetsTypes(0 /*types */);
+ lp.setFitInsetsTypes(0 /*types */);
switch (mWindowManager.getDefaultDisplay().getRotation()) {
case Surface.ROTATION_0:
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index fe4879b0b071..3af80387778b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -175,7 +175,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
- mLp.setFitWindowInsetsTypes(0 /* types */);
+ mLp.setFitInsetsTypes(0 /* types */);
mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("NotificationShade");
mLp.packageName = mContext.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
index 6979554303b3..7650a3ab3a4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowInsets.Type.systemBars;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.LayoutRes;
@@ -81,7 +83,7 @@ public class NotificationShadeWindowView extends FrameLayout {
@Override
public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
- final Insets insets = windowInsets.getMaxInsets(WindowInsets.Type.systemBars());
+ final Insets insets = windowInsets.getInsetsIgnoringVisibility(systemBars());
if (getFitsSystemWindows()) {
boolean paddingChanged = insets.top != getPaddingTop()
|| insets.bottom != getPaddingBottom();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 7558022df96d..41d896856daa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -37,7 +37,6 @@ import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
import android.util.Log;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -174,7 +173,7 @@ public class PhoneStatusBarPolicy
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -614,7 +613,7 @@ public class PhoneStatusBarPolicy
case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:
updateVolumeZen();
break;
- case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
+ case Intent.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index fb30bdec68b5..e448d0ac8649 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -107,6 +107,7 @@ public class StatusBarWindowController {
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
+ mLp.setFitInsetsTypes(0 /* types */);
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 28b6c389d4df..06105f532eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -106,8 +106,8 @@ public class SystemUIDialog extends AlertDialog {
if (Dependency.get(KeyguardStateController.class).isShowing()) {
final Window window = dialog.getWindow();
window.setType(LayoutParams.TYPE_STATUS_BAR_PANEL);
- window.setFitWindowInsetsTypes(
- window.getFitWindowInsetsTypes() & ~Type.statusBars());
+ window.getAttributes().setFitInsetsTypes(
+ window.getAttributes().getFitInsetsTypes() & ~Type.statusBars());
} else {
dialog.getWindow().setType(LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
}
@@ -118,8 +118,8 @@ public class SystemUIDialog extends AlertDialog {
window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- window.setFitWindowInsetsTypes(
- window.getFitWindowInsetsTypes() & ~Type.statusBars());
+ window.getAttributes().setFitInsetsTypes(
+ window.getAttributes().getFitInsetsTypes() & ~Type.statusBars());
return dialog;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index e675a7f373b6..5dc91047770d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -29,7 +29,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dependency;
@@ -137,9 +136,9 @@ public class EmergencyCryptkeeperText extends TextView {
displayText = getContext().getText(
com.android.internal.R.string.emergency_calls_only);
Intent i = getContext().registerReceiver(null,
- new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
+ new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED));
if (i != null) {
- displayText = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+ displayText = i.getStringExtra(TelephonyManager.EXTRA_PLMN);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index a76d41c12709..3a1feaa2de14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -41,7 +41,6 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.SignalStrengthUtil;
@@ -430,12 +429,12 @@ public class MobileSignalController extends SignalController<
public void handleBroadcast(Intent intent) {
String action = intent.getAction();
- if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
- updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
- intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
- intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
- intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
- intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
+ if (action.equals(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)) {
+ updateNetworkName(intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false),
+ intent.getStringExtra(TelephonyManager.EXTRA_SPN),
+ intent.getStringExtra(TelephonyManager.EXTRA_DATA_SPN),
+ intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false),
+ intent.getStringExtra(TelephonyManager.EXTRA_PLMN));
notifyListenersIfNecessary();
} else if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
updateDataSim();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 899279d46161..6dd113377ce7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -315,11 +315,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
filter.addAction(Intent.ACTION_SERVICE_STATE);
- filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+ filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
@@ -524,7 +524,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mConfig = Config.readConfig(mContext);
mReceiverHandler.post(this::handleConfigurationChanged);
break;
- case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
+ case Intent.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 718522c9908a..6baf36c81d30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -54,7 +54,8 @@ public class WifiSignalController extends
mWifiTracker.setListening(true);
mHasMobileData = hasMobileData;
if (wifiManager != null) {
- wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback());
+ wifiManager.registerTrafficStateCallback(context.getMainExecutor(),
+ new WifiTrafficStateCallback());
}
// WiFi only has one state.
mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
index 6cc8dd908760..eb1af7c82324 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java
@@ -16,20 +16,23 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.Bundle;
-import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
@@ -41,36 +44,53 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+import com.android.systemui.util.Assert;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class ForegroundCoordinatorTest extends SysuiTestCase {
private static final String TEST_PKG = "test_pkg";
private static final int NOTIF_USER_ID = 0;
- @Mock private Handler mMainHandler;
@Mock private ForegroundServiceController mForegroundServiceController;
@Mock private AppOpsController mAppOpsController;
@Mock private NotifPipeline mNotifPipeline;
+ @Captor private ArgumentCaptor<AppOpsController.Callback> mAppOpsCaptor;
+
private NotificationEntry mEntry;
private Notification mNotification;
private ForegroundCoordinator mForegroundCoordinator;
private NotifFilter mForegroundFilter;
+ private AppOpsController.Callback mAppOpsCallback;
private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
+ private FakeSystemClock mClock = new FakeSystemClock();
+ private FakeExecutor mExecutor = new FakeExecutor(mClock);
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mForegroundCoordinator = new ForegroundCoordinator(
- mForegroundServiceController, mAppOpsController, mMainHandler);
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
+ mForegroundCoordinator =
+ new ForegroundCoordinator(
+ mForegroundServiceController,
+ mAppOpsController,
+ mExecutor);
mNotification = new Notification();
mEntry = new NotificationEntryBuilder()
@@ -86,9 +106,11 @@ public class ForegroundCoordinatorTest extends SysuiTestCase {
verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender(
lifetimeExtenderCaptor.capture());
+ verify(mAppOpsController).addCallback(any(int[].class), mAppOpsCaptor.capture());
mForegroundFilter = filterCaptor.getValue();
mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
+ mAppOpsCallback = mAppOpsCaptor.getValue();
}
@Test
@@ -183,4 +205,74 @@ public class ForegroundCoordinatorTest extends SysuiTestCase {
assertFalse(mForegroundNotifLifetimeExtender
.shouldExtendLifetime(mEntry, NotificationListenerService.REASON_CLICK));
}
+
+ @Test
+ public void testAppOpsAreApplied() {
+ // GIVEN Three current notifications, two with the same key but from different users
+ NotificationEntry entry1 = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setPkg(TEST_PKG)
+ .setId(1)
+ .build();
+ NotificationEntry entry2 = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setPkg(TEST_PKG)
+ .setId(2)
+ .build();
+ NotificationEntry entry2Other = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID + 1))
+ .setPkg(TEST_PKG)
+ .setId(2)
+ .build();
+ when(mNotifPipeline.getActiveNotifs()).thenReturn(List.of(entry1, entry2, entry2Other));
+
+ // GIVEN that entry2 is currently associated with a foreground service
+ when(mForegroundServiceController.getStandardLayoutKey(0, TEST_PKG))
+ .thenReturn(entry2.getKey());
+
+ // WHEN a new app ops code comes in
+ mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, true);
+ mExecutor.runAllReady();
+
+ // THEN entry2's app ops are updated, but no one else's are
+ assertEquals(
+ new ArraySet<>(),
+ entry1.mActiveAppOps);
+ assertEquals(
+ new ArraySet<>(List.of(47)),
+ entry2.mActiveAppOps);
+ assertEquals(
+ new ArraySet<>(),
+ entry2Other.mActiveAppOps);
+ }
+
+ @Test
+ public void testAppOpsAreRemoved() {
+ // GIVEN One notification which is associated with app ops
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .setPkg(TEST_PKG)
+ .setId(2)
+ .build();
+ when(mNotifPipeline.getActiveNotifs()).thenReturn(List.of(entry));
+ when(mForegroundServiceController.getStandardLayoutKey(0, TEST_PKG))
+ .thenReturn(entry.getKey());
+
+ // GIVEN that the notification's app ops are already [47, 33]
+ mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, true);
+ mAppOpsCallback.onActiveStateChanged(33, NOTIF_USER_ID, TEST_PKG, true);
+ mExecutor.runAllReady();
+ assertEquals(
+ new ArraySet<>(List.of(47, 33)),
+ entry.mActiveAppOps);
+
+ // WHEN one of the app ops is removed
+ mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, false);
+ mExecutor.runAllReady();
+
+ // THEN the entry's active app ops are updated as well
+ assertEquals(
+ new ArraySet<>(List.of(33)),
+ entry.mActiveAppOps);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index cd89d3c32697..4406248ec9ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -36,7 +36,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
@@ -411,13 +410,13 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
boolean showPlmn, String plmn) {
Intent intent = new Intent();
- intent.setAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+ intent.setAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
- intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
- intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
+ intent.putExtra(TelephonyManager.EXTRA_SHOW_SPN, showSpn);
+ intent.putExtra(TelephonyManager.EXTRA_SPN, spn);
- intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
- intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
+ intent.putExtra(TelephonyManager.EXTRA_SHOW_PLMN, showPlmn);
+ intent.putExtra(TelephonyManager.EXTRA_PLMN, plmn);
SubscriptionManager.putSubscriptionIdExtra(intent, mSubId);
return intent;
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 264ce440f59f..b0ef15399435 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -36,6 +36,7 @@ java_library {
sdk_version: "system_current",
srcs: [
"src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
":framework-tethering-annotations",
],
static_libs: [
@@ -63,10 +64,13 @@ filegroup {
name: "framework-tethering-srcs",
srcs: [
"src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
"src/android/net/IIntResultListener.aidl",
"src/android/net/ITetheringEventCallback.aidl",
"src/android/net/ITetheringConnector.aidl",
+ "src/android/net/TetheringCallbackStartedParcel.aidl",
"src/android/net/TetheringConfigurationParcel.aidl",
+ "src/android/net/TetheringRequestParcel.aidl",
"src/android/net/TetherStatesParcel.aidl",
],
path: "src"
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index d30c39986984..5febe73288bf 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -17,6 +17,7 @@ package android.net;
import android.net.IIntResultListener;
import android.net.ITetheringEventCallback;
+import android.net.TetheringRequestParcel;
import android.os.ResultReceiver;
/** @hide */
@@ -27,8 +28,8 @@ oneway interface ITetheringConnector {
void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);
- void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi,
- String callerPkg);
+ void startTethering(in TetheringRequestParcel request, String callerPkg,
+ IIntResultListener receiver);
void stopTethering(int type, String callerPkg, IIntResultListener receiver);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index 28361954e11e..28a810dbfac3 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -18,6 +18,7 @@ package android.net;
import android.net.Network;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetherStatesParcel;
/**
@@ -26,8 +27,8 @@ import android.net.TetherStatesParcel;
*/
oneway interface ITetheringEventCallback
{
- void onCallbackStarted(in Network network, in TetheringConfigurationParcel config,
- in TetherStatesParcel states);
+ /** Called immediately after the callbacks are registered */
+ void onCallbackStarted(in TetheringCallbackStartedParcel parcel);
void onCallbackStopped(int errorCode);
void onUpstreamChanged(in Network network);
void onConfigurationChanged(in TetheringConfigurationParcel config);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
new file mode 100644
index 000000000000..14ee2d3e5d38
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.Network;
+import android.net.TetheringConfigurationParcel;
+import android.net.TetherStatesParcel;
+
+/**
+ * Initial information reported by tethering upon callback registration.
+ * @hide
+ */
+parcelable TetheringCallbackStartedParcel {
+ boolean tetheringSupported;
+ Network upstreamNetwork;
+ TetheringConfigurationParcel config;
+ TetherStatesParcel states;
+} \ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
new file mode 100644
index 000000000000..00cf98e0fc2d
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.ResultReceiver;
+
+/**
+ * Collections of constants for internal tethering usage.
+ *
+ * <p>These hidden constants are not in TetheringManager as they are not part of the API stubs
+ * generated for TetheringManager, which prevents the tethering module from linking them at
+ * build time.
+ * TODO: investigate changing the tethering build rules so that Tethering can reference hidden
+ * symbols from framework-tethering even when they are in a non-hidden class.
+ * @hide
+ */
+public class TetheringConstants {
+ /**
+ * 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";
+ /**
+ * 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";
+ /**
+ * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+ * provisioning.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+ /**
+ * Tells the TetherService to run a provision check now.
+ *
+ * {@hide}
+ */
+ 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.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 11e57186c666..58bc4e7633ce 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,9 +15,14 @@
*/
package android.net;
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Context;
-import android.net.ConnectivityManager.OnTetheringEventCallback;
+import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.RemoteException;
@@ -25,6 +30,11 @@ import android.os.ResultReceiver;
import android.util.ArrayMap;
import android.util.Log;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -34,7 +44,8 @@ import java.util.concurrent.Executor;
*
* @hide
*/
-// TODO: make it @SystemApi
+@SystemApi
+@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
private static final int DEFAULT_TIMEOUT_MS = 60_000;
@@ -44,7 +55,7 @@ public class TetheringManager {
private final ITetheringConnector mConnector;
private final TetheringCallbackInternal mCallback;
private final Context mContext;
- private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback>
+ private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
mTetheringEventCallbacks = new ArrayMap<>();
private TetheringConfigurationParcel mTetheringConfiguration;
@@ -72,7 +83,7 @@ public class TetheringManager {
* 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 = "android.net.extra.ACTIVE_LOCAL_ONLY";
/**
* gives a String[] listing all the interfaces currently tethered
@@ -118,35 +129,6 @@ public class TetheringManager {
*/
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;
@@ -160,12 +142,14 @@ public class TetheringManager {
public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
public static final int TETHER_ERROR_PROVISION_FAILED = 11;
public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
- public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
+ public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
/**
* Create a TetheringManager object for interacting with the tethering service.
+ *
+ * {@hide}
*/
public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
mContext = context;
@@ -229,10 +213,9 @@ public class TetheringManager {
private final ConditionVariable mWaitForCallback = new ConditionVariable();
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
- mTetheringConfiguration = config;
- mTetherStatesParcel = states;
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+ mTetheringConfiguration = parcel.config;
+ mTetherStatesParcel = parcel.states;
mWaitForCallback.open();
}
@@ -275,6 +258,8 @@ public class TetheringManager {
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ *
+ * {@hide}
*/
@Deprecated
public int tether(@NonNull final String iface) {
@@ -296,6 +281,8 @@ public class TetheringManager {
*
* @deprecated The only usages is PanService. It uses this for legacy reasons
* and will migrate away as soon as possible.
+ *
+ * {@hide}
*/
@Deprecated
public int untether(@NonNull final String iface) {
@@ -320,6 +307,8 @@ public class TetheringManager {
* #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
* not have any upstream.
+ *
+ * {@hide}
*/
@Deprecated
public int setUsbTethering(final boolean enable) {
@@ -338,27 +327,171 @@ public class TetheringManager {
}
/**
+ * Use with {@link #startTethering} to specify additional parameters when starting tethering.
+ */
+ public static class TetheringRequest {
+ /** A configuration set for TetheringRequest. */
+ private final TetheringRequestParcel mRequestParcel;
+
+ private TetheringRequest(final TetheringRequestParcel request) {
+ mRequestParcel = request;
+ }
+
+ /** Builder used to create TetheringRequest. */
+ public static class Builder {
+ private final TetheringRequestParcel mBuilderParcel;
+
+ /** Default constructor of Builder. */
+ public Builder(final int type) {
+ mBuilderParcel = new TetheringRequestParcel();
+ mBuilderParcel.tetheringType = type;
+ mBuilderParcel.localIPv4Address = null;
+ mBuilderParcel.exemptFromEntitlementCheck = false;
+ mBuilderParcel.showProvisioningUi = true;
+ }
+
+ /**
+ * Configure tethering with static IPv4 assignment (with DHCP disabled).
+ *
+ * @param localIPv4Address The preferred local IPv4 address to use.
+ */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) {
+ mBuilderParcel.localIPv4Address = localIPv4Address;
+ return this;
+ }
+
+ /** Start tethering without entitlement checks. */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder setExemptFromEntitlementCheck(boolean exempt) {
+ mBuilderParcel.exemptFromEntitlementCheck = exempt;
+ return this;
+ }
+
+ /** Start tethering without showing the provisioning UI. */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder setSilentProvisioning(boolean silent) {
+ mBuilderParcel.showProvisioningUi = silent;
+ return this;
+ }
+
+ /** Build {@link TetheringRequest] with the currently set configuration. */
+ @NonNull
+ public TetheringRequest build() {
+ return new TetheringRequest(mBuilderParcel);
+ }
+ }
+
+ /**
+ * Get a TetheringRequestParcel from the configuration
+ * @hide
+ */
+ public TetheringRequestParcel getParcel() {
+ return mRequestParcel;
+ }
+
+ /** String of TetheringRequest detail. */
+ public String toString() {
+ return "TetheringRequest [ type= " + mRequestParcel.tetheringType
+ + ", localIPv4Address= " + mRequestParcel.localIPv4Address
+ + ", exemptFromEntitlementCheck= "
+ + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
+ + mRequestParcel.showProvisioningUi + " ]";
+ }
+ }
+
+ /**
+ * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+ */
+ public abstract static class StartTetheringCallback {
+ /**
+ * Called when tethering has been successfully started.
+ */
+ public void onTetheringStarted() {}
+
+ /**
+ * Called when starting tethering failed.
+ *
+ * @param resultCode One of the {@code TETHER_ERROR_*} constants.
+ */
+ public void onTetheringFailed(final int resultCode) {}
+ }
+
+ /**
* Starts tethering and runs tether provisioning for the given type if needed. If provisioning
* fails, stopTethering will be called automatically.
*
- */
- // TODO: improve the usage of ResultReceiver, b/145096122
- public void startTethering(final int type, @NonNull final ResultReceiver receiver,
- final boolean showProvisioningUi) {
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param request a {@link TetheringRequest} which can specify the preferred configuration.
+ * @param executor {@link Executor} to specify the thread upon which the callback of
+ * TetheringRequest will be invoked.
+ * @param callback A callback that will be called to indicate the success status of the
+ * tethering start request.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void startTethering(@NonNull final TetheringRequest request,
+ @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "startTethering caller:" + callerPkg);
+ final IIntResultListener listener = new IIntResultListener.Stub() {
+ @Override
+ public void onResult(final int resultCode) {
+ executor.execute(() -> {
+ if (resultCode == TETHER_ERROR_NO_ERROR) {
+ callback.onTetheringStarted();
+ } else {
+ callback.onTetheringFailed(resultCode);
+ }
+ });
+ }
+ };
try {
- mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg);
+ mConnector.startTethering(request.getParcel(), callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
/**
+ * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
+ * fails, stopTethering will be called automatically.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
+ * @param executor {@link Executor} to specify the thread upon which the callback of
+ * TetheringRequest will be invoked.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void startTethering(int type, @NonNull final Executor executor,
+ @NonNull final StartTetheringCallback callback) {
+ startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
+ }
+
+ /**
* Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
* applicable.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
public void stopTethering(final int type) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopTethering caller:" + callerPkg);
@@ -375,11 +508,69 @@ public class TetheringManager {
}
/**
+ * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
+ * entitlement succeeded.
+ */
+ public interface OnTetheringEntitlementResultListener {
+ /**
+ * Called to notify entitlement result.
+ *
+ * @param resultCode an int value of entitlement result. It may be one of
+ * {@link #TETHER_ERROR_NO_ERROR},
+ * {@link #TETHER_ERROR_PROVISION_FAILED}, or
+ * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+ */
+ void onTetheringEntitlementResult(int resultCode);
+ }
+
+ /**
* Request the latest value of the tethering entitlement check.
*
- * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
- * out some such apps are observed to abuse this API, change to per-UID limits on this API
- * if it's really needed.
+ * <p>This method will only return the latest entitlement result if it is available. If no
+ * cached entitlement result is available, and {@code showEntitlementUi} is false,
+ * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
+ * true, entitlement will be run.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
+ * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
+ * @param executor the executor on which callback will be invoked.
+ * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
+ * notify the caller of the result of entitlement check. The listener may be called zero
+ * or one time.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void requestLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
+ @NonNull Executor executor,
+ @NonNull final OnTetheringEntitlementResultListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException(
+ "OnTetheringEntitlementResultListener cannot be null.");
+ }
+
+ ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ executor.execute(() -> {
+ listener.onTetheringEntitlementResult(resultCode);
+ });
+ }
+ };
+
+ requestLatestTetheringEntitlementResult(type, wrappedListener,
+ showEntitlementUi);
+ }
+
+ /**
+ * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
+ * with ConnectivityManager#getLatestTetheringEntitlementResult
+ *
+ * {@hide}
*/
// TODO: improve the usage of ResultReceiver, b/145096122
public void requestLatestTetheringEntitlementResult(final int type,
@@ -396,25 +587,148 @@ public class TetheringManager {
}
/**
+ * Callback for use with {@link registerTetheringEventCallback} to find out tethering
+ * upstream status.
+ */
+ public abstract static class TetheringEventCallback {
+ /**
+ * Called when tethering supported status changed.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ *
+ * <p>Tethering may be disabled via system properties, device configuration, or device
+ * policy restrictions.
+ *
+ * @param supported The new supported status
+ */
+ public void onTetheringSupported(boolean supported) {}
+
+ /**
+ * Called when tethering upstream changed.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ *
+ * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
+ * have any upstream.
+ */
+ public void onUpstreamChanged(@Nullable Network network) {}
+
+ /**
+ * Called when there was a change in tethering interface regular expressions.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param reg The new regular expressions.
+ * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+ */
+ @Deprecated
+ public void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
+
+ /**
+ * Called when there was a change in the list of tetherable interfaces.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param interfaces The list of tetherable interfaces.
+ */
+ public void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
+
+ /**
+ * Called when there was a change in the list of tethered interfaces.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param interfaces The list of tethered interfaces.
+ */
+ public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
+
+ /**
+ * Called when an error occurred configuring tethering.
+ *
+ * <p>This will be called immediately after the callback is registered if the latest status
+ * on the interface is an error, and may be called multiple times later upon changes.
+ * @param ifName Name of the interface.
+ * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
+ */
+ public void onError(@NonNull String ifName, int error) {}
+ }
+
+ /**
+ * Regular expressions used to identify tethering interfaces.
+ * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+ */
+ @Deprecated
+ public static class TetheringInterfaceRegexps {
+ private final String[] mTetherableBluetoothRegexs;
+ private final String[] mTetherableUsbRegexs;
+ private final String[] mTetherableWifiRegexs;
+
+ public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
+ @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
+ mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
+ mTetherableUsbRegexs = tetherableUsbRegexs.clone();
+ mTetherableWifiRegexs = tetherableWifiRegexs.clone();
+ }
+
+ @NonNull
+ public List<String> getTetherableBluetoothRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
+ }
+
+ @NonNull
+ public List<String> getTetherableUsbRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
+ }
+
+ @NonNull
+ public List<String> getTetherableWifiRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
+ mTetherableWifiRegexs);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof TetheringInterfaceRegexps)) return false;
+ final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
+ return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
+ && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
+ && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
+ }
+ }
+
+ /**
* Start listening to tethering change events. Any new added callback will receive the last
* tethering status right away. If callback is registered,
- * {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
+ * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
* has no upstream or disabled, the argument of callback will be null. The same callback object
* cannot be registered twice.
*
* @param executor the executor on which callback will be invoked.
* @param callback the callback to be called when tethering has change events.
*/
+ @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
public void registerTetheringEventCallback(@NonNull Executor executor,
- @NonNull OnTetheringEventCallback callback) {
+ @NonNull TetheringEventCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
synchronized (mTetheringEventCallbacks) {
- if (!mTetheringEventCallbacks.containsKey(callback)) {
+ if (mTetheringEventCallbacks.containsKey(callback)) {
throw new IllegalArgumentException("callback was already registered.");
}
final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
+ // Only accessed with a lock on this object
+ private final HashMap<String, Integer> mErrorStates = new HashMap<>();
+ private String[] mLastTetherableInterfaces = null;
+ private String[] mLastTetheredInterfaces = null;
+
@Override
public void onUpstreamChanged(Network network) throws RemoteException {
executor.execute(() -> {
@@ -422,11 +736,45 @@ public class TetheringManager {
});
}
+ private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
+ for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
+ final String iface = newStates.erroredIfaceList[i];
+ final Integer lastError = mErrorStates.get(iface);
+ final int newError = newStates.lastErrorList[i];
+ if (newError != TETHER_ERROR_NO_ERROR
+ && !Objects.equals(lastError, newError)) {
+ callback.onError(iface, newError);
+ }
+ mErrorStates.put(iface, newError);
+ }
+ }
+
+ private synchronized void maybeSendTetherableIfacesChangedCallback(
+ final TetherStatesParcel newStates) {
+ if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
+ mLastTetherableInterfaces = newStates.availableList.clone();
+ callback.onTetherableInterfacesChanged(
+ Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
+ }
+
+ private synchronized void maybeSendTetheredIfacesChangedCallback(
+ final TetherStatesParcel newStates) {
+ if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
+ mLastTetheredInterfaces = newStates.tetheredList.clone();
+ callback.onTetheredInterfacesChanged(
+ Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
+ }
+
+ // Called immediately after the callbacks are registered.
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
executor.execute(() -> {
- callback.onUpstreamChanged(network);
+ callback.onTetheringSupported(parcel.tetheringSupported);
+ callback.onUpstreamChanged(parcel.upstreamNetwork);
+ sendErrorCallbacks(parcel.states);
+ sendRegexpsChanged(parcel.config);
+ maybeSendTetherableIfacesChangedCallback(parcel.states);
+ maybeSendTetheredIfacesChangedCallback(parcel.states);
});
}
@@ -437,11 +785,26 @@ public class TetheringManager {
});
}
+ private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
+ callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
+ parcel.tetherableBluetoothRegexs,
+ parcel.tetherableUsbRegexs,
+ parcel.tetherableWifiRegexs));
+ }
+
@Override
- public void onConfigurationChanged(TetheringConfigurationParcel config) { }
+ public void onConfigurationChanged(TetheringConfigurationParcel config) {
+ executor.execute(() -> sendRegexpsChanged(config));
+ }
@Override
- public void onTetherStatesChanged(TetherStatesParcel states) { }
+ public void onTetherStatesChanged(TetherStatesParcel states) {
+ executor.execute(() -> {
+ sendErrorCallbacks(states);
+ maybeSendTetherableIfacesChangedCallback(states);
+ maybeSendTetheredIfacesChangedCallback(states);
+ });
+ }
};
try {
mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
@@ -458,7 +821,11 @@ public class TetheringManager {
*
* @param callback previously registered callback.
*/
- public void unregisterTetheringEventCallback(@NonNull final OnTetheringEventCallback callback) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.TETHER_PRIVILEGED,
+ Manifest.permission.ACCESS_NETWORK_STATE
+ })
+ public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
@@ -482,6 +849,7 @@ public class TetheringManager {
* @param iface The name of the interface of interest
* @return error The error code of the last error tethering or untethering the named
* interface
+ * @hide
*/
public int getLastTetherError(@NonNull final String iface) {
mCallback.waitForStarted();
@@ -503,6 +871,7 @@ public class TetheringManager {
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable usb interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableUsbRegexs() {
mCallback.waitForStarted();
@@ -516,6 +885,7 @@ public class TetheringManager {
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable wifi interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableWifiRegexs() {
mCallback.waitForStarted();
@@ -529,6 +899,7 @@ public class TetheringManager {
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable bluetooth interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableBluetoothRegexs() {
mCallback.waitForStarted();
@@ -540,6 +911,7 @@ public class TetheringManager {
* device configuration and current interface existence.
*
* @return an array of 0 or more Strings of tetherable interface names.
+ * @hide
*/
public @NonNull String[] getTetherableIfaces() {
mCallback.waitForStarted();
@@ -552,6 +924,7 @@ public class TetheringManager {
* Get the set of tethered interfaces.
*
* @return an array of 0 or more String of currently tethered interface names.
+ * @hide
*/
public @NonNull String[] getTetheredIfaces() {
mCallback.waitForStarted();
@@ -570,6 +943,7 @@ public class TetheringManager {
*
* @return an array of 0 or more String indicating the interface names
* which failed to tether.
+ * @hide
*/
public @NonNull String[] getTetheringErroredIfaces() {
mCallback.waitForStarted();
@@ -582,6 +956,7 @@ public class TetheringManager {
* Get the set of tethered dhcp ranges.
*
* @deprecated This API just return the default value which is not used in DhcpServer.
+ * @hide
*/
@Deprecated
public @NonNull String[] getTetheredDhcpRanges() {
@@ -595,6 +970,7 @@ public class TetheringManager {
* due to device configuration.
*
* @return a boolean - {@code true} indicating Tethering is supported.
+ * @hide
*/
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
@@ -613,7 +989,14 @@ public class TetheringManager {
/**
* Stop all active tethering.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
public void stopAllTethering() {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopAllTethering caller:" + callerPkg);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
new file mode 100644
index 000000000000..bf19d85f6a83
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.LinkAddress;
+
+/**
+ * Configuration details for requesting tethering.
+ * @hide
+ */
+parcelable TetheringRequestParcel {
+ int tetheringType;
+ LinkAddress localIPv4Address;
+ boolean exemptFromEntitlementCheck;
+ boolean showProvisioningUi;
+}
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 1cabc8d0b5b7..e81d6ac7a588 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -16,14 +16,14 @@
package com.android.server.connectivity.tethering;
-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.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringConstants.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_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
@@ -577,7 +577,7 @@ public class EntitlementManager {
private static String errorString(int value) {
switch (value) {
- case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
+ case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
default:
@@ -657,7 +657,7 @@ public class EntitlementManager {
}
final int cacheValue = mEntitlementCacheValue.get(
- downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
+ downstream, TETHER_ERROR_ENTITLEMENT_UNKNOWN);
if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
receiver.send(cacheValue, null);
} else {
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 8d1e0c96e300..c47f2d6d4db2 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -66,6 +66,7 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.IIntResultListener;
import android.net.INetd;
import android.net.ITetheringEventCallback;
import android.net.IpPrefix;
@@ -74,7 +75,9 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
import android.net.ip.IpServer;
import android.net.shared.NetdUtils;
import android.net.util.BaseNetdUnsolicitedEventListener;
@@ -423,9 +426,10 @@ public class Tethering {
}
}
- void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
- mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
- enableTetheringInternal(type, true /* enabled */, receiver);
+ void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
+ mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
+ request.showProvisioningUi);
+ enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
}
void stopTethering(int type) {
@@ -437,29 +441,32 @@ public class Tethering {
* Enables or disables tethering for the given type. If provisioning is required, it will
* schedule provisioning rechecks for the specified interface.
*/
- private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
+ private void enableTetheringInternal(int type, boolean enable,
+ final IIntResultListener listener) {
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
break;
case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, receiver);
+ setBluetoothTethering(enable, listener);
break;
default:
Log.w(TAG, "Invalid tether type.");
- sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
+ sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
}
}
- private void sendTetherResult(ResultReceiver receiver, int result) {
- if (receiver != null) {
- receiver.send(result, null);
+ private void sendTetherResult(final IIntResultListener listener, int result) {
+ if (listener != null) {
+ try {
+ listener.onResult(result);
+ } catch (RemoteException e) { }
}
}
@@ -485,12 +492,12 @@ public class Tethering {
return TETHER_ERROR_MASTER_ERROR;
}
- private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
+ private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
if (adapter == null || !adapter.isEnabled()) {
Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
+ (adapter == null));
- sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
+ sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL);
return;
}
@@ -519,7 +526,7 @@ public class Tethering {
final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
? TETHER_ERROR_NO_ERROR
: TETHER_ERROR_MASTER_ERROR;
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
}
}, BluetoothProfile.PAN);
@@ -951,6 +958,7 @@ public class Tethering {
mWrapper.showTetheredNotification(
R.drawable.stat_sys_tether_general, false);
mWrapper.untetherAll();
+ // TODO(b/148139325): send tetheringSupported on restriction change
}
}
}
@@ -1844,9 +1852,13 @@ public class Tethering {
void registerTetheringEventCallback(ITetheringEventCallback callback) {
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback);
+ final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
+ parcel.tetheringSupported = mDeps.isTetheringSupported();
+ parcel.upstreamNetwork = mTetherUpstream;
+ parcel.config = mConfig.toStableParcelable();
+ parcel.states = mTetherStatesParcel;
try {
- callback.onCallbackStarted(mTetherUpstream, mConfig.toStableParcelable(),
- mTetherStatesParcel);
+ callback.onCallbackStarted(parcel);
} catch (RemoteException e) {
// Not really very much to do here.
}
@@ -1881,6 +1893,7 @@ public class Tethering {
for (int i = 0; i < length; i++) {
try {
mTetheringEventCallbacks.getBroadcastItem(i).onConfigurationChanged(config);
+ // TODO(b/148139325): send tetheringSupported on configuration change
} catch (RemoteException e) {
// Not really very much to do here.
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index cb7d3920e693..7dc5c5f2db8a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -33,6 +33,7 @@ import android.net.ITetheringConnector;
import android.net.ITetheringEventCallback;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
@@ -143,11 +144,11 @@ public class TetheringService extends Service {
}
@Override
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
- String callerPkg) {
- if (checkAndNotifyCommonError(callerPkg, receiver)) return;
+ public void startTethering(TetheringRequestParcel request, String callerPkg,
+ IIntResultListener listener) {
+ if (checkAndNotifyCommonError(callerPkg, listener)) return;
- mTethering.startTethering(type, receiver, showProvisioningUi);
+ mTethering.startTethering(request, listener);
}
@Override
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 4f0746199786..3a1d4a61a39e 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
@@ -19,7 +19,7 @@ package com.android.server.connectivity.tethering;
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_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -110,7 +110,7 @@ public final class EntitlementManagerTest {
}
public class WrappedEntitlementManager extends EntitlementManager {
- public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
public int uiProvisionCount = 0;
public int silentProvisionCount = 0;
@@ -120,7 +120,7 @@ public final class EntitlementManagerTest {
}
public void reset() {
- fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
uiProvisionCount = 0;
silentProvisionCount = 0;
}
@@ -274,7 +274,7 @@ public final class EntitlementManagerTest {
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
mCallbacklatch.countDown();
}
};
@@ -343,7 +343,7 @@ public final class EntitlementManagerTest {
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
mCallbacklatch.countDown();
}
};
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 d6afa4744d26..6fc0c659f397 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
@@ -86,7 +86,9 @@ import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
@@ -467,6 +469,16 @@ public class TetheringTest {
return new Tethering(mTetheringDependencies);
}
+ private TetheringRequestParcel createTetheringRquestParcel(final int type) {
+ final TetheringRequestParcel request = new TetheringRequestParcel();
+ request.tetheringType = type;
+ request.localIPv4Address = null;
+ request.exemptFromEntitlementCheck = false;
+ request.showProvisioningUi = false;
+
+ return request;
+ }
+
@After
public void tearDown() {
mServiceContext.unregisterReceiver(mBroadcastReceiver);
@@ -572,7 +584,7 @@ public class TetheringTest {
.thenReturn(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
- mTethering.startTethering(TETHERING_USB, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null);
mLooper.dispatchAll();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
@@ -818,7 +830,7 @@ public class TetheringTest {
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
@@ -845,7 +857,7 @@ public class TetheringTest {
when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
@@ -922,7 +934,7 @@ public class TetheringTest {
doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startTetheredHotspot(null);
verifyNoMoreInteractions(mWifiManager);
@@ -1113,11 +1125,10 @@ public class TetheringTest {
}
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
- mActualUpstreams.add(network);
- mTetheringConfigs.add(config);
- mTetherStates.add(states);
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+ mActualUpstreams.add(parcel.upstreamNetwork);
+ mTetheringConfigs.add(parcel.config);
+ mTetherStates.add(parcel.states);
}
@Override
@@ -1188,7 +1199,7 @@ public class TetheringTest {
tetherState = callback.pollTetherStatesChanged();
assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
tetherState = callback.pollTetherStatesChanged();
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index ad802ff879f2..54b420191deb 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -312,5 +312,9 @@ message SystemMessage {
// Notify the user that data or apps are being moved to external storage.
// Package: com.android.systemui
NOTE_STORAGE_MOVE = 0x534d4f56;
+
+ // Notify the user that the admin suspended personal apps on the device.
+ // Package: android
+ NOTE_PERSONAL_APPS_SUSPENDED = 1003;
}
}
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
index 5e6f97e4f282..c7be80cd538b 100644
--- a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
@@ -20,7 +20,6 @@ import static com.android.server.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.slice.Slice;
import android.content.Context;
import android.os.RemoteException;
import android.service.autofill.Dataset;
@@ -123,7 +122,8 @@ public final class InlineSuggestionFactory {
// TODO(b/146453195): fill in the autofill hint properly.
final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
inlinePresentation.getInlinePresentationSpec(),
- InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""});
+ InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION);
final View.OnClickListener onClickListener = v -> {
try {
client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
@@ -132,7 +132,7 @@ public final class InlineSuggestionFactory {
}
};
final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
- createInlineContentProvider(inlinePresentation.getSlice(), inlineSuggestionUi,
+ createInlineContentProvider(inlinePresentation, inlineSuggestionUi,
onClickListener));
return inlineSuggestion;
}
@@ -146,25 +146,28 @@ public final class InlineSuggestionFactory {
// TODO(b/146453195): fill in the autofill hint properly.
final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
inlinePresentation.getInlinePresentationSpec(),
- InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""});
+ InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION);
final View.OnClickListener onClickListener = v -> {
client.fill(requestId, fieldIndex, dataset);
};
final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
- createInlineContentProvider(inlinePresentation.getSlice(), inlineSuggestionUi,
+ createInlineContentProvider(inlinePresentation, inlineSuggestionUi,
onClickListener));
return inlineSuggestion;
}
private static IInlineContentProvider.Stub createInlineContentProvider(
- @NonNull Slice slice, @NonNull InlineSuggestionUi inlineSuggestionUi,
+ @NonNull InlinePresentation inlinePresentation,
+ @NonNull InlineSuggestionUi inlineSuggestionUi,
@Nullable View.OnClickListener onClickListener) {
return new IInlineContentProvider.Stub() {
@Override
public void provideContent(int width, int height,
IInlineContentCallback callback) {
UiThread.getHandler().post(() -> {
- SurfaceControl sc = inlineSuggestionUi.inflate(slice, width, height,
+ SurfaceControl sc = inlineSuggestionUi.inflate(inlinePresentation, width,
+ height,
onClickListener);
try {
callback.onContent(sc);
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
index 2460732d17dc..2adefeabfcc8 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
@@ -25,10 +25,17 @@ import android.annotation.Nullable;
import android.app.slice.Slice;
import android.app.slice.SliceItem;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.drawable.Icon;
+import android.graphics.fonts.SystemFonts;
import android.os.IBinder;
+import android.service.autofill.InlinePresentation;
+import android.text.TextUtils;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -41,6 +48,8 @@ import android.widget.TextView;
import com.android.internal.R;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This is a temporary inline suggestion UI inflater which will be replaced by the ExtServices
@@ -54,6 +63,10 @@ public class InlineSuggestionUi {
private static final String TAG = "InlineSuggestionUi";
+ // The pattern to match the value can be obtained by calling {@code Resources#getResourceName
+ // (int)}. This name is a single string of the form "package:type/entry".
+ private static final Pattern RESOURCE_NAME_PATTERN = Pattern.compile("([^:]+):([^/]+)/(\\S+)");
+
private final Context mContext;
public InlineSuggestionUi(Context context) {
@@ -65,28 +78,36 @@ public class InlineSuggestionUi {
*/
@MainThread
@Nullable
- public SurfaceControl inflate(@NonNull Slice slice, int width, int height,
- @Nullable View.OnClickListener onClickListener) {
+ public SurfaceControl inflate(@NonNull InlinePresentation inlinePresentation, int width,
+ int height, @Nullable View.OnClickListener onClickListener) {
Log.d(TAG, "Inflating the inline suggestion UI");
//TODO(b/137800469): Pass in inputToken from IME.
final SurfaceControlViewHost wvr = new SurfaceControlViewHost(mContext,
mContext.getDisplay(), (IBinder) null);
final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
- final ViewGroup suggestionView = (ViewGroup) renderSlice(slice);
+
+ Context contextThemeWrapper = getContextThemeWrapper(mContext,
+ inlinePresentation.getInlinePresentationSpec().getStyle());
+ if (contextThemeWrapper == null) {
+ contextThemeWrapper = getDefaultContextThemeWrapper(mContext);
+ }
+ final View suggestionView = renderSlice(inlinePresentation.getSlice(),
+ contextThemeWrapper);
if (onClickListener != null) {
suggestionView.setOnClickListener(onClickListener);
}
WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(width, height,
- WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0,
+ PixelFormat.TRANSPARENT);
wvr.addView(suggestionView, lp);
return sc;
}
- private View renderSlice(Slice slice) {
- final LayoutInflater inflater = LayoutInflater.from(mContext);
+ private static View renderSlice(Slice slice, Context context) {
+ final LayoutInflater inflater = LayoutInflater.from(context);
final ViewGroup suggestionView =
(ViewGroup) inflater.inflate(R.layout.autofill_inline_suggestion, null);
@@ -137,4 +158,96 @@ public class InlineSuggestionUi {
return suggestionView;
}
+
+ private Context getDefaultContextThemeWrapper(@NonNull Context context) {
+ Resources.Theme theme = context.getResources().newTheme();
+ theme.applyStyle(android.R.style.Theme_AutofillInlineSuggestion, true);
+ return new ContextThemeWrapper(context, theme);
+ }
+
+ /**
+ * Returns a context wrapping the theme in the provided {@code style}, or null if {@code
+ * style} doesn't pass validation.
+ */
+ @Nullable
+ private static Context getContextThemeWrapper(@NonNull Context context,
+ @Nullable String style) {
+ if (style == null) {
+ return null;
+ }
+ Matcher matcher = RESOURCE_NAME_PATTERN.matcher(style);
+ if (!matcher.matches()) {
+ Log.d(TAG, "Can not parse the style=" + style);
+ return null;
+ }
+ String packageName = matcher.group(1);
+ String type = matcher.group(2);
+ String entry = matcher.group(3);
+ if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(type) || TextUtils.isEmpty(entry)) {
+ Log.d(TAG, "Can not proceed with empty field values in the style=" + style);
+ return null;
+ }
+ Resources resources = null;
+ try {
+ resources = context.getPackageManager().getResourcesForApplication(
+ packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ int resId = resources.getIdentifier(entry, type, packageName);
+ if (resId == Resources.ID_NULL) {
+ return null;
+ }
+ Resources.Theme theme = resources.newTheme();
+ theme.applyStyle(resId, true);
+ if (!validateBaseTheme(theme, resId)) {
+ Log.d(TAG, "Provided theme is not a child of Theme.InlineSuggestion, ignoring it.");
+ return null;
+ }
+ if (!validateFontFamilyForTextViewStyles(theme)) {
+ Log.d(TAG,
+ "Provided theme specifies a font family that is not system font, ignoring it.");
+ return null;
+ }
+ return new ContextThemeWrapper(context, theme);
+ }
+
+ private static boolean validateFontFamilyForTextViewStyles(Resources.Theme theme) {
+ return validateFontFamily(theme, android.R.attr.autofillInlineSuggestionTitle)
+ && validateFontFamily(theme, android.R.attr.autofillInlineSuggestionSubtitle);
+ }
+
+ private static boolean validateFontFamily(Resources.Theme theme, int styleAttr) {
+ TypedArray ta = null;
+ try {
+ ta = theme.obtainStyledAttributes(null, new int[]{android.R.attr.fontFamily},
+ styleAttr,
+ 0);
+ if (ta.getIndexCount() == 0) {
+ return true;
+ }
+ String fontFamily = ta.getString(ta.getIndex(0));
+ return SystemFonts.getRawSystemFallbackMap().containsKey(fontFamily);
+ } finally {
+ if (ta != null) {
+ ta.recycle();
+ }
+ }
+ }
+
+ private static boolean validateBaseTheme(Resources.Theme theme, int styleAttr) {
+ TypedArray ta = null;
+ try {
+ ta = theme.obtainStyledAttributes(null,
+ new int[]{android.R.attr.isAutofillInlineSuggestionTheme}, styleAttr, 0);
+ if (ta.getIndexCount() == 0) {
+ return false;
+ }
+ return ta.getBoolean(ta.getIndex(0), false);
+ } finally {
+ if (ta != null) {
+ ta.recycle();
+ }
+ }
+ }
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 5e10916c4491..0bcf45d4a526 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.os.SELinux;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -399,6 +400,12 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
* the transport have no data.
*/
private void informTransportOfUnchangedApps(Set<String> appsBackedUp) {
+ // If the feautre is not enabled then we just exit early.
+ if (!FeatureFlagUtils.isEnabled(mBackupManagerService.getContext(),
+ FeatureFlagUtils.BACKUP_NO_KV_DATA_CHANGE_CALLS)) {
+ return;
+ }
+
String[] succeedingPackages = getSucceedingPackages();
if (succeedingPackages == null) {
// Nothing is succeeding, so end early.
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index e976811a3094..434a97ee0bc5 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -361,13 +361,18 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
@Override
- public boolean isDeviceAssociated(String packageName, String macAddress, int userId) {
+ public boolean isDeviceAssociatedForWifiConnection(String packageName, String macAddress,
+ int userId) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_COMPANION_DEVICES, "isDeviceAssociated");
+ boolean bypassMacPermission = getContext().getPackageManager().checkPermission(
+ android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS, packageName)
+ == PackageManager.PERMISSION_GRANTED;
+
return CollectionUtils.any(
readAllAssociations(userId, packageName),
- a -> Objects.equals(a.deviceAddress, macAddress));
+ a -> bypassMacPermission || Objects.equals(a.deviceAddress, macAddress));
}
private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1691a96b0dc4..a603fa975b74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -113,6 +113,7 @@ java_library_static {
"android.hardware.broadcastradio-V2.0-java",
"android.hardware.health-V1.0-java",
"android.hardware.health-V2.0-java",
+ "android.hardware.light-java",
"android.hardware.weaver-V1.0-java",
"android.hardware.biometrics.face-V1.0-java",
"android.hardware.biometrics.fingerprint-V2.1-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 368416b0d4a1..994c3147d70c 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -33,6 +33,7 @@ import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ComponentParseUtils;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -169,7 +170,7 @@ public abstract class PackageManagerInternal {
* Return a List of all application packages that are installed on the
* device, for a specific user. If flag GET_UNINSTALLED_PACKAGES has been
* set, a list of all applications including those deleted with
- * {@code DONT_DELETE_DATA} (partially installed apps with data directory)
+ * {@code DELETE_KEEP_DATA} (partially installed apps with data directory)
* will be returned.
*
* @param flags Additional option flags to modify the data returned.
@@ -183,7 +184,7 @@ public abstract class PackageManagerInternal {
* information is retrieved from the list of uninstalled
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
- * deleted with {@code DONT_DELETE_DATA} flag set).
+ * deleted with {@code DELETE_KEEP_DATA} flag set).
*/
public abstract List<ApplicationInfo> getInstalledApplications(
@ApplicationInfoFlags int flags, @UserIdInt int userId, int callingUid);
@@ -689,6 +690,27 @@ public abstract class PackageManagerInternal {
int userId);
/**
+ * Return the processes that have been declared for a uid.
+ *
+ * @param uid The uid to query.
+ *
+ * @return Returns null if there are no declared processes for the uid; otherwise,
+ * returns the set of processes it declared.
+ */
+ public abstract ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
+
+ /**
+ * Return the gids associated with a particular permission.
+ *
+ * @param permissionName The name of the permission to query.
+ * @param userId The user id the gids will be associated with.
+ *
+ * @return Returns null if there are no gids associated with the permission, otherwise an
+ * array if the gid ints.
+ */
+ public abstract int[] getPermissionGids(String permissionName, int userId);
+
+ /**
* Return if device is currently in a "core" boot environment, typically
* used to support full-disk encryption. Only apps marked with
* {@code coreApp} attribute are available.
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index a33fcd557369..8074900d2776 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -66,8 +66,8 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
import java.io.File;
import java.io.FileDescriptor;
@@ -1065,7 +1065,7 @@ public final class BatteryService extends SystemService {
}
private final class Led {
- private final Light mBatteryLight;
+ private final LogicalLight mBatteryLight;
private final int mBatteryLowARGB;
private final int mBatteryMediumARGB;
@@ -1100,7 +1100,7 @@ public final class BatteryService extends SystemService {
mBatteryLight.setColor(mBatteryLowARGB);
} else {
// Flash red when battery is low and not charging
- mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
+ mBatteryLight.setFlashing(mBatteryLowARGB, LogicalLight.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e9db9c819ab7..de0b6fcbd4ae 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -18,6 +18,8 @@ package com.android.server;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
@@ -35,14 +37,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.Signature;
-import android.content.res.Resources;
-import android.hardware.location.ActivityRecognitionHardware;
import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
@@ -52,6 +47,7 @@ import android.location.IBatchedLocationCallback;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
+import android.location.IGpsGeofenceHardware;
import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.Location;
@@ -91,11 +87,11 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.AbstractLocationProvider.State;
-import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GeofenceProxy;
+import com.android.server.location.HardwareActivityRecognitionProxy;
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderProxy;
import com.android.server.location.LocationRequestStatistics;
@@ -114,7 +110,6 @@ import java.io.FileDescriptor;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -123,6 +118,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
@@ -543,77 +539,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@GuardedBy("mLock")
- private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
- PackageManager pm = mContext.getPackageManager();
- String systemPackageName = mContext.getPackageName();
- ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
-
- List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
- new Intent(FUSED_LOCATION_SERVICE_ACTION),
- PackageManager.GET_META_DATA, mUserInfoStore.getCurrentUserId());
- for (ResolveInfo rInfo : rInfos) {
- String packageName = rInfo.serviceInfo.packageName;
-
- // Check that the signature is in the list of supported sigs. If it's not in
- // this list the standard provider binding logic won't bind to it.
- try {
- PackageInfo pInfo;
- pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
- if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
- Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
- ", but has wrong signature, ignoring");
- continue;
- }
- } catch (NameNotFoundException e) {
- Log.e(TAG, "missing package: " + packageName);
- continue;
- }
-
- // Get the version info
- if (rInfo.serviceInfo.metaData == null) {
- Log.w(TAG, "Found fused provider without metadata: " + packageName);
- continue;
- }
-
- int version = rInfo.serviceInfo.metaData.getInt(
- ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
- if (version == 0) {
- // This should be the fallback fused location provider.
-
- // Make sure it's in the system partition.
- if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
- continue;
- }
-
- // Check that the fallback is signed the same as the OS
- // as a proxy for coreApp="true"
- if (pm.checkSignatures(systemPackageName, packageName)
- != PackageManager.SIGNATURE_MATCH) {
- if (D) {
- Log.d(TAG, "Fallback candidate not signed the same as system: "
- + packageName);
- }
- continue;
- }
-
- // Found a valid fallback.
- if (D) Log.d(TAG, "Found fallback provider: " + packageName);
- return;
- } else {
- if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
- }
- }
-
- throw new IllegalStateException("Unable to find a fused location provider that is in the "
- + "system partition with version 0 and signed with the platform certificate. "
- + "Such a package is needed to provide a default fused location provider in the "
- + "event that no other fused location provider has been installed or is currently "
- + "available. For example, coreOnly boot mode when decrypting the data "
- + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
- }
-
- @GuardedBy("mLock")
private void initializeProvidersLocked() {
if (GnssManagerService.isGnssSupported()) {
mGnssManagerService = new GnssManagerService(this, mContext, mLocationUsageLogger);
@@ -622,33 +547,11 @@ public class LocationManagerService extends ILocationManager.Stub {
gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
}
- /*
- Load package name(s) containing location provider support.
- These packages can contain services implementing location providers:
- Geocoder Provider, Network Location Provider, and
- Fused Location Provider. They will each be searched for
- service components implementing these providers.
- The location framework also has support for installation
- of new location providers at run-time. The new package does not
- have to be explicitly listed here, however it must have a signature
- that matches the signature of at least one package on this list.
- */
- Resources resources = mContext.getResources();
- String[] pkgs = resources.getStringArray(
- com.android.internal.R.array.config_locationProviderPackageNames);
- if (D) {
- Log.d(TAG, "certificates for location providers pulled from: " +
- Arrays.toString(pkgs));
- }
-
- ensureFallbackFusedProviderPresentLocked(pkgs);
-
- LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
+ LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
mContext,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
- com.android.internal.R.string.config_networkLocationProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames);
+ com.android.internal.R.string.config_networkLocationProviderPackageName);
if (networkProvider != null) {
LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER);
mProviderManagers.add(networkManager);
@@ -657,13 +560,18 @@ public class LocationManagerService extends ILocationManager.Stub {
Slog.w(TAG, "no network location provider found");
}
+ // ensure that a fused provider exists which will work in direct boot
+ Preconditions.checkState(!mContext.getPackageManager().queryIntentServicesAsUser(
+ new Intent(FUSED_LOCATION_SERVICE_ACTION),
+ MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
+ "Unable to find a direct boot aware fused location provider");
+
// bind to fused provider
- LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
+ LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
mContext,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
- com.android.internal.R.string.config_fusedLocationProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames);
+ com.android.internal.R.string.config_fusedLocationProviderPackageName);
if (fusedProvider != null) {
LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER);
mProviderManagers.add(fusedManager);
@@ -674,47 +582,30 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// bind to geocoder provider
- mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
- com.android.internal.R.bool.config_enableGeocoderOverlay,
- com.android.internal.R.string.config_geocoderProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames);
+ mGeocodeProvider = GeocoderProxy.createAndRegister(mContext);
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
+ // bind to geofence proxy
if (mGnssManagerService != null) {
- // bind to geofence provider
- GeofenceProxy provider = GeofenceProxy.createAndBind(
- mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
- com.android.internal.R.string.config_geofenceProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames,
- mGnssManagerService.getGpsGeofenceProxy(),
- null);
- if (provider == null) {
- Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
+ IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
+ if (gpsGeofenceHardware != null) {
+ GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
+ if (provider == null) {
+ Slog.d(TAG, "unable to bind to GeofenceProxy");
+ }
}
}
// bind to hardware activity recognition
- boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
- ActivityRecognitionHardware activityRecognitionHardware = null;
- if (activityRecognitionHardwareIsSupported) {
- activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
- } else {
- Slog.d(TAG, "Hardware Activity-Recognition not supported.");
- }
- ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
- mContext,
- activityRecognitionHardwareIsSupported,
- activityRecognitionHardware,
- com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
- com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
- com.android.internal.R.array.config_locationProviderPackageNames);
- if (proxy == null) {
- Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
+ HardwareActivityRecognitionProxy hardwareActivityRecognitionProxy =
+ HardwareActivityRecognitionProxy.createAndRegister(mContext);
+ if (hardwareActivityRecognitionProxy == null) {
+ Log.e(TAG, "unable to bind ActivityRecognitionProxy");
}
- String[] testProviderStrings = resources.getStringArray(
+ String[] testProviderStrings = mContext.getResources().getStringArray(
com.android.internal.R.array.config_testLocationProviders);
for (String testProviderString : testProviderStrings) {
String[] fragments = testProviderString.split(",");
@@ -2996,10 +2887,12 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println("Historical Records by Provider:");
ipw.increaseIndent();
+ TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>();
+ sorted.putAll(mRequestStatistics.statistics);
for (Map.Entry<PackageProviderKey, PackageStatistics> entry
- : mRequestStatistics.statistics.entrySet()) {
+ : sorted.entrySet()) {
PackageProviderKey key = entry.getKey();
- ipw.println(key.packageName + ": " + key.providerName + ": " + entry.getValue());
+ ipw.println(key.providerName + ": " + key.packageName + ": " + entry.getValue());
}
ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index e8e3b39d5112..131a22b07c7b 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -18,6 +18,7 @@ package com.android.server;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,14 +26,18 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.os.Build;
+import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
import android.os.RecoverySystem;
+import android.os.RemoteCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.MathUtils;
@@ -46,10 +51,16 @@ import com.android.server.PackageWatchdog.FailureReasons;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import com.android.server.am.SettingsToPropertiesMapper;
-import com.android.server.utils.FlagNamespaceUtils;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Utilities to help rescue the system from crash loops. Callers are expected to
@@ -64,8 +75,6 @@ public class RescueParty {
@VisibleForTesting
static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
@VisibleForTesting
- static final int TRIGGER_COUNT = 5;
- @VisibleForTesting
static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
@VisibleForTesting
static final int LEVEL_NONE = 0;
@@ -81,6 +90,8 @@ public class RescueParty {
static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
@VisibleForTesting
static final String TAG = "RescueParty";
+ @VisibleForTesting
+ static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
private static final String NAME = "rescue-party-observer";
@@ -139,7 +150,11 @@ public class RescueParty {
*/
public static void onSettingsProviderPublished(Context context) {
handleNativeRescuePartyResets();
- executeRescueLevel(context);
+ executeRescueLevel(context, /*failedPackage=*/ null);
+ ContentResolver contentResolver = context.getContentResolver();
+ Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> {
+ handleMonitorCallback(context, result);
+ }));
}
@VisibleForTesting
@@ -147,10 +162,53 @@ public class RescueParty {
return SystemClock.elapsedRealtime();
}
+ private static void handleMonitorCallback(Context context, Bundle result) {
+ String callbackType = result.getString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, "");
+ switch (callbackType) {
+ case Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK:
+ String updatedNamespace = result.getString(Settings.EXTRA_NAMESPACE);
+ if (updatedNamespace != null) {
+ startObservingPackages(context, updatedNamespace);
+ }
+ break;
+ case Settings.EXTRA_ACCESS_CALLBACK:
+ String callingPackage = result.getString(Settings.EXTRA_CALLING_PACKAGE, null);
+ String namespace = result.getString(Settings.EXTRA_NAMESPACE, null);
+ if (namespace != null && callingPackage != null) {
+ RescuePartyObserver.getInstance(context).recordDeviceConfigAccess(
+ callingPackage,
+ namespace);
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unrecognized DeviceConfig callback");
+ break;
+ }
+ }
+
+ private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+ Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace);
+ if (callingPackages == null) {
+ return;
+ }
+ List<String> callingPackageList = new ArrayList<>();
+ callingPackageList.addAll(callingPackages);
+ Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
+ + updatedNamespace);
+ PackageWatchdog.getInstance(context).startObservingHealth(
+ rescuePartyObserver,
+ callingPackageList,
+ DEFAULT_OBSERVING_DURATION_MS);
+ }
+
private static void handleNativeRescuePartyResets() {
if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
- FlagNamespaceUtils.resetDeviceConfig(Settings.RESET_MODE_TRUSTED_DEFAULTS,
- Arrays.asList(SettingsToPropertiesMapper.getResetNativeCategories()));
+ String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
+ for (int i = 0; i < resetNativeCategories.length; i++) {
+ DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ resetNativeCategories[i]);
+ }
}
}
@@ -164,7 +222,7 @@ public class RescueParty {
/**
* Escalate to the next rescue level. After incrementing the level you'll
- * probably want to call {@link #executeRescueLevel(Context)}.
+ * probably want to call {@link #executeRescueLevel(Context, String)}.
*/
private static void incrementRescueLevel(int triggerUid) {
final int level = MathUtils.constrain(
@@ -177,13 +235,13 @@ public class RescueParty {
+ levelToString(level) + " triggered by UID " + triggerUid);
}
- private static void executeRescueLevel(Context context) {
+ private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
if (level == LEVEL_NONE) return;
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
try {
- executeRescueLevelInternal(context, level);
+ executeRescueLevelInternal(context, level, failedPackage);
EventLogTags.writeRescueSuccess(level);
logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
@@ -195,24 +253,23 @@ public class RescueParty {
}
}
- private static void executeRescueLevelInternal(Context context, int level) throws Exception {
+ private static void executeRescueLevelInternal(Context context, int level, @Nullable
+ String failedPackage) throws Exception {
StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level);
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage);
break;
case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, failedPackage);
break;
case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
break;
case LEVEL_FACTORY_RESET:
RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
break;
}
- FlagNamespaceUtils.addToKnownResetNamespaces(
- FlagNamespaceUtils.NAMESPACE_NO_PACKAGE);
}
private static int mapRescueLevelToUserImpact(int rescueLevel) {
@@ -237,13 +294,14 @@ public class RescueParty {
}
}
- private static void resetAllSettings(Context context, int mode) throws Exception {
+ private static void resetAllSettings(Context context, int mode, @Nullable String failedPackage)
+ throws Exception {
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
final ContentResolver resolver = context.getContentResolver();
try {
- FlagNamespaceUtils.resetDeviceConfig(mode);
+ resetDeviceConfig(context, mode, failedPackage);
} catch (Exception e) {
res = new RuntimeException("Failed to reset config settings", e);
}
@@ -264,6 +322,41 @@ public class RescueParty {
}
}
+ private static void resetDeviceConfig(Context context, int resetMode,
+ @Nullable String failedPackage) {
+ if (!shouldPerformScopedResets() || failedPackage == null) {
+ DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
+ } else {
+ performScopedReset(context, resetMode, failedPackage);
+ }
+ }
+
+ private static boolean shouldPerformScopedResets() {
+ int rescueLevel = MathUtils.constrain(
+ SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE),
+ LEVEL_NONE, LEVEL_FACTORY_RESET);
+ return rescueLevel <= LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+ }
+
+ private static void performScopedReset(Context context, int resetMode,
+ @NonNull String failedPackage) {
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+ Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet(
+ failedPackage);
+ if (affectedNamespaces == null) {
+ DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
+ } else {
+ Slog.w(TAG,
+ "Performing scoped reset for package: " + failedPackage
+ + ", affected namespaces: "
+ + Arrays.toString(affectedNamespaces.toArray()));
+ Iterator<String> it = affectedNamespaces.iterator();
+ while (it.hasNext()) {
+ DeviceConfig.resetToDefaults(resetMode, it.next());
+ }
+ }
+ }
+
/**
* Handle mitigation action for package failures. This observer will be register to Package
* Watchdog and will receive calls about package failures. This observer is persistent so it
@@ -271,7 +364,9 @@ public class RescueParty {
*/
public static class RescuePartyObserver implements PackageHealthObserver {
- private Context mContext;
+ private final Context mContext;
+ private final Map<String, Set<String>> mCallingPackageNamespaceSetMap = new HashMap<>();
+ private final Map<String, Set<String>> mNamespaceCallingPackageSetMap = new HashMap<>();
@GuardedBy("RescuePartyObserver.class")
static RescuePartyObserver sRescuePartyObserver;
@@ -290,6 +385,13 @@ public class RescueParty {
}
}
+ @VisibleForTesting
+ static void reset() {
+ synchronized (RescuePartyObserver.class) {
+ sRescuePartyObserver = null;
+ }
+ }
+
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
@FailureReasons int failureReason) {
@@ -314,7 +416,8 @@ public class RescueParty {
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
int triggerUid = getPackageUid(mContext, failedPackage.getPackageName());
incrementRescueLevel(triggerUid);
- executeRescueLevel(mContext);
+ executeRescueLevel(mContext,
+ failedPackage == null ? null : failedPackage.getPackageName());
return true;
} else {
return false;
@@ -355,7 +458,7 @@ public class RescueParty {
return false;
}
incrementRescueLevel(Process.ROOT_UID);
- executeRescueLevel(mContext);
+ executeRescueLevel(mContext, /*failedPackage=*/ null);
return true;
}
@@ -363,6 +466,32 @@ public class RescueParty {
public String getName() {
return NAME;
}
+
+ private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
+ @NonNull String namespace) {
+ // Record it in calling packages to namespace map
+ Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
+ if (namespaceSet == null) {
+ namespaceSet = new ArraySet<>();
+ mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+ }
+ namespaceSet.add(namespace);
+ // Record it in namespace to calling packages map
+ Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
+ if (callingPackageSet == null) {
+ callingPackageSet = new ArraySet<>();
+ }
+ callingPackageSet.add(callingPackage);
+ mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
+ }
+
+ private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
+ return mCallingPackageNamespaceSetMap.get(failedPackage);
+ }
+
+ private synchronized Set<String> getCallingPackagesSet(String namespace) {
+ return mNamespaceCallingPackageSetMap.get(namespace);
+ }
}
private static int[] getAllUserIds() {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 7f51aa9068fc..8564cb456ba6 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,7 +16,19 @@
package com.android.server;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_NOT_FOREGROUND;
+import static android.content.Context.BIND_NOT_VISIBLE;
+import static android.content.pm.PackageManager.GET_META_DATA;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import android.annotation.BoolRes;
import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -24,11 +36,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.content.pm.Signature;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
@@ -37,15 +45,10 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.Preconditions;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
@@ -55,16 +58,16 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
- * Find the best Service, and bind to it.
- * Handles run-time package changes.
+ * Maintains a binding to the best service that matches the given intent information. Bind and
+ * unbind callbacks, as well as all binder operations, will all be run on the given handler.
*/
public class ServiceWatcher implements ServiceConnection {
private static final String TAG = "ServiceWatcher";
- private static final boolean D = false;
+ private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
- public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
- public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
+ private static final String EXTRA_SERVICE_VERSION = "serviceVersion";
+ private static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
private static final long BLOCKING_BINDER_TIMEOUT_MS = 30 * 1000;
@@ -83,280 +86,300 @@ public class ServiceWatcher implements ServiceConnection {
T run(IBinder binder) throws RemoteException;
}
- public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
- String... packageNames) {
- PackageManager pm = context.getPackageManager();
+ /**
+ * Information on the service ServiceWatcher has selected as the best option for binding.
+ */
+ public static final class ServiceInfo implements Comparable<ServiceInfo> {
- ArrayList<HashSet<Signature>> signatureSets = new ArrayList<>(packageNames.length);
- for (String packageName : packageNames) {
- try {
- Signature[] signatures = pm.getPackageInfo(packageName,
- PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.GET_SIGNATURES).signatures;
-
- HashSet<Signature> set = new HashSet<>();
- Collections.addAll(set, signatures);
- signatureSets.add(set);
- } catch (NameNotFoundException e) {
- Log.w(TAG, packageName + " not found");
+ public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
+ UserHandle.USER_NULL);
+
+ public final int version;
+ @Nullable public final ComponentName component;
+ @UserIdInt public final int userId;
+
+ private ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
+ Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
+
+ Bundle metadata = resolveInfo.serviceInfo.metaData;
+ boolean isMultiuser;
+ if (metadata != null) {
+ version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
+ isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
+ } else {
+ version = Integer.MIN_VALUE;
+ isMultiuser = false;
}
- }
- return signatureSets;
- }
- /** Checks if signatures match. */
- public static boolean isSignatureMatch(Signature[] signatures,
- List<HashSet<Signature>> sigSets) {
- if (signatures == null) return false;
+ component = resolveInfo.serviceInfo.getComponentName();
+ userId = isMultiuser ? UserHandle.USER_SYSTEM : currentUserId;
+ }
- // build hashset of input to test against
- HashSet<Signature> inputSet = new HashSet<>();
- Collections.addAll(inputSet, signatures);
+ private ServiceInfo(int version, @Nullable ComponentName component, int userId) {
+ Preconditions.checkArgument(component != null || version == Integer.MIN_VALUE);
+ this.version = version;
+ this.component = component;
+ this.userId = userId;
+ }
- // test input against each of the signature sets
- for (HashSet<Signature> referenceSet : sigSets) {
- if (referenceSet.equals(inputSet)) {
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
return true;
}
+ if (!(o instanceof ServiceInfo)) {
+ return false;
+ }
+ ServiceInfo that = (ServiceInfo) o;
+ return version == that.version && userId == that.userId
+ && Objects.equals(component, that.component);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(version, component, userId);
+ }
+
+ @Override
+ public int compareTo(ServiceInfo that) {
+ // ServiceInfos with higher version numbers always win (having a version number >
+ // MIN_VALUE implies having a non-null component). if version numbers are equal, a
+ // non-null component wins over a null component. if the version numbers are equal and
+ // both components exist then we prefer components that work for all users vs components
+ // that only work for a single user at a time. otherwise everything's equal.
+ int ret = Integer.compare(version, that.version);
+ if (ret == 0) {
+ if (component == null && that.component != null) {
+ ret = -1;
+ } else if (component != null && that.component == null) {
+ ret = 1;
+ } else {
+ if (userId != UserHandle.USER_SYSTEM && that.userId == UserHandle.USER_SYSTEM) {
+ ret = -1;
+ } else if (userId == UserHandle.USER_SYSTEM
+ && that.userId != UserHandle.USER_SYSTEM) {
+ ret = 1;
+ }
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public String toString() {
+ return component + "@" + version + "[u" + userId + "]";
}
- return false;
}
private final Context mContext;
- private final String mTag;
- private final String mAction;
- private final String mServicePackageName;
- private final List<HashSet<Signature>> mSignatureSets;
-
private final Handler mHandler;
+ private final Intent mIntent;
+
+ @Nullable private final BinderRunner mOnBind;
+ @Nullable private final Runnable mOnUnbind;
- // read/write from handler thread
- private IBinder mBestService;
+ // read/write from handler thread only
private int mCurrentUserId;
- // read from any thread, write from handler thread
- private volatile ComponentName mBestComponent;
- private volatile int mBestVersion;
- private volatile int mBestUserId;
+ // write from handler thread only, read anywhere
+ private volatile ServiceInfo mServiceInfo;
- public ServiceWatcher(Context context, String logTag, String action,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler) {
- Resources resources = context.getResources();
+ // read/write from handler thread only
+ private IBinder mBinder;
+ public ServiceWatcher(Context context, Handler handler, String action,
+ @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
+ @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
mContext = context;
- mTag = logTag;
- mAction = action;
-
- boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
- if (enableOverlay) {
- String[] pkgs = resources.getStringArray(initialPackageNamesResId);
- mServicePackageName = null;
- mSignatureSets = getSignatureSets(context, pkgs);
- if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
- } else {
- mServicePackageName = resources.getString(defaultServicePackageNameResId);
- mSignatureSets = getSignatureSets(context, mServicePackageName);
- if (D) Log.d(mTag, "Overlay disabled, default package=" + mServicePackageName);
+ mHandler = FgThread.getHandler();
+ mIntent = new Intent(Objects.requireNonNull(action));
+
+ Resources resources = context.getResources();
+ boolean enableOverlay = resources.getBoolean(enableOverlayResId);
+ if (!enableOverlay) {
+ mIntent.setPackage(resources.getString(nonOverlayPackageResId));
}
- mHandler = handler;
+ mOnBind = onBind;
+ mOnUnbind = onUnbind;
- mBestComponent = null;
- mBestVersion = Integer.MIN_VALUE;
- mBestUserId = UserHandle.USER_NULL;
+ mCurrentUserId = UserHandle.USER_NULL;
- mBestService = null;
+ mServiceInfo = ServiceInfo.NONE;
+ mBinder = null;
}
- protected void onBind() {}
-
- protected void onUnbind() {}
-
/**
- * Start this watcher, including binding to the current best match and
- * re-binding to any better matches down the road.
- * <p>
- * Note that if there are no matching encryption-aware services, we may not
- * bind to a real service until after the current user is unlocked.
- *
- * @return {@code true} if a potential service implementation was found.
+ * Register this class, which will start the process of determining the best matching service
+ * and maintaining a binding to it. Will return false and fail if there are no possible matching
+ * services at the time this functions is called.
*/
- public final boolean start() {
- // if we have to return false, do it before registering anything
- if (isServiceMissing()) return false;
-
- // listen for relevant package changes if service overlay is enabled on handler
- if (mServicePackageName == null) {
- new PackageMonitor() {
- @Override
- public void onPackageUpdateFinished(String packageName, int uid) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
- }
+ public boolean register() {
+ if (mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM).isEmpty()) {
+ return false;
+ }
- @Override
- public void onPackageAdded(String packageName, int uid) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
- }
+ new PackageMonitor() {
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ ServiceWatcher.this.onPackageChanged(packageName);
+ }
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
- }
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ ServiceWatcher.this.onPackageChanged(packageName);
+ }
- @Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
- return super.onPackageChanged(packageName, uid, components);
- }
- }.register(mContext, UserHandle.ALL, true, mHandler);
- }
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ ServiceWatcher.this.onPackageChanged(packageName);
+ }
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ ServiceWatcher.this.onPackageChanged(packageName);
+ return super.onPackageChanged(packageName, uid, components);
+ }
+ }.register(mContext, UserHandle.ALL, true, mHandler);
- // listen for user change on handler
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL);
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mCurrentUserId = userId;
- bindBestPackage(false);
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- if (userId == mCurrentUserId) {
- bindBestPackage(false);
- }
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ return;
}
+
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ onUserSwitched(userId);
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ onUserUnlocked(userId);
+ break;
+ default:
+ break;
+ }
+
}
}, UserHandle.ALL, intentFilter, null, mHandler);
mCurrentUserId = ActivityManager.getCurrentUser();
- mHandler.post(() -> bindBestPackage(false));
+ mHandler.post(() -> onBestServiceChanged(false));
return true;
}
- /** Returns the name of the currently connected package or null. */
- @Nullable
- public String getCurrentPackageName() {
- ComponentName bestComponent = mBestComponent;
- return bestComponent == null ? null : bestComponent.getPackageName();
- }
-
- private boolean isServiceMissing() {
- return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.USER_SYSTEM).isEmpty();
+ /**
+ * Returns information on the currently selected service.
+ */
+ public ServiceInfo getBoundService() {
+ return mServiceInfo;
}
- private void bindBestPackage(boolean forceRebind) {
+ private void onBestServiceChanged(boolean forceRebind) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- Intent intent = new Intent(mAction);
- if (mServicePackageName != null) {
- intent.setPackage(mServicePackageName);
- }
-
- List<ResolveInfo> rInfos = mContext.getPackageManager().queryIntentServicesAsUser(intent,
- PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
+ mIntent,
+ GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
mCurrentUserId);
- if (rInfos == null) {
- rInfos = Collections.emptyList();
+
+ ServiceInfo bestServiceInfo = ServiceInfo.NONE;
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
+ if (serviceInfo.compareTo(bestServiceInfo) > 0) {
+ bestServiceInfo = serviceInfo;
+ }
}
- ComponentName bestComponent = null;
- int bestVersion = Integer.MIN_VALUE;
- boolean bestIsMultiuser = false;
+ if (forceRebind || !bestServiceInfo.equals(mServiceInfo)) {
+ rebind(bestServiceInfo);
+ }
+ }
- for (ResolveInfo rInfo : rInfos) {
- ComponentName component = rInfo.serviceInfo.getComponentName();
- String packageName = component.getPackageName();
+ private void rebind(ServiceInfo newServiceInfo) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- // check signature
- try {
- PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES
- | PackageManager.MATCH_DIRECT_BOOT_AUTO);
- if (!isSignatureMatch(pInfo.signatures, mSignatureSets)) {
- Log.w(mTag, packageName + " resolves service " + mAction
- + ", but has wrong signature, ignoring");
- continue;
- }
- } catch (NameNotFoundException e) {
- Log.wtf(mTag, e);
- continue;
+ if (!mServiceInfo.equals(ServiceInfo.NONE)) {
+ if (D) {
+ Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mServiceInfo);
}
- // check metadata
- Bundle metadata = rInfo.serviceInfo.metaData;
- int version = Integer.MIN_VALUE;
- boolean isMultiuser = false;
- if (metadata != null) {
- version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
- isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
- }
+ mContext.unbindService(this);
+ mServiceInfo = ServiceInfo.NONE;
+ }
- if (version > bestVersion) {
- bestComponent = component;
- bestVersion = version;
- bestIsMultiuser = isMultiuser;
- }
+ mServiceInfo = newServiceInfo;
+ if (mServiceInfo.equals(ServiceInfo.NONE)) {
+ return;
}
+ Preconditions.checkState(mServiceInfo.component != null);
+
if (D) {
- Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
- (mServicePackageName == null ? ""
- : "(" + mServicePackageName + ") "), rInfos.size(),
- (bestComponent == null ? "no new best component"
- : "new best component: " + bestComponent)));
+ Log.i(TAG, getLogPrefix() + " binding to " + mServiceInfo);
}
- if (bestComponent == null) {
- Slog.w(mTag, "Odd, no component found for service " + mAction);
- unbind();
- return;
+ Intent bindIntent = new Intent(mIntent).setComponent(mServiceInfo.component);
+ mContext.bindServiceAsUser(bindIntent, this,
+ BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
+ mHandler, UserHandle.of(mServiceInfo.userId));
+ }
+
+ @Override
+ public final void onServiceConnected(ComponentName component, IBinder binder) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ if (D) {
+ Log.i(TAG, getLogPrefix() + " connected to " + component);
}
- int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
- boolean alreadyBound = Objects.equals(bestComponent, mBestComponent)
- && bestVersion == mBestVersion && userId == mBestUserId;
- if (forceRebind || !alreadyBound) {
- unbind();
- bind(bestComponent, bestVersion, userId);
+ mBinder = binder;
+ if (mOnBind != null) {
+ runOnBinder(mOnBind);
}
}
- private void bind(ComponentName component, int version, int userId) {
+ @Override
+ public final void onServiceDisconnected(ComponentName component) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- Intent intent = new Intent(mAction);
- intent.setComponent(component);
-
- mBestComponent = component;
- mBestVersion = version;
- mBestUserId = userId;
+ if (D) {
+ Log.i(TAG, getLogPrefix() + " disconnected from " + component);
+ }
- if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
- mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
- UserHandle.of(userId));
+ mBinder = null;
+ if (mOnUnbind != null) {
+ mOnUnbind.run();
+ }
}
- private void unbind() {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ private void onUserSwitched(@UserIdInt int userId) {
+ mCurrentUserId = userId;
+ onBestServiceChanged(false);
+ }
- if (mBestComponent != null) {
- if (D) Log.d(mTag, "unbinding " + mBestComponent);
- mContext.unbindService(this);
+ private void onUserUnlocked(@UserIdInt int userId) {
+ if (userId == mCurrentUserId) {
+ onBestServiceChanged(false);
}
+ }
- mBestComponent = null;
- mBestVersion = Integer.MIN_VALUE;
- mBestUserId = UserHandle.USER_NULL;
+ private void onPackageChanged(String packageName) {
+ // force a rebind if the changed package was the currently connected package
+ String currentPackageName =
+ mServiceInfo.component != null ? mServiceInfo.component.getPackageName() : null;
+ onBestServiceChanged(packageName.equals(currentPackageName));
}
/**
@@ -365,26 +388,26 @@ public class ServiceWatcher implements ServiceConnection {
*/
public final void runOnBinder(BinderRunner runner) {
runOnHandler(() -> {
- if (mBestService == null) {
+ if (mBinder == null) {
return;
}
try {
- runner.run(mBestService);
- } catch (RuntimeException e) {
- // the code being run is privileged, but may be outside the system server, and thus
- // we cannot allow runtime exceptions to crash the system server
- Log.e(TAG, "exception while while running " + runner + " on " + mBestService
- + " from " + this, e);
- } catch (RemoteException e) {
- // do nothing
+ runner.run(mBinder);
+ } catch (RuntimeException | RemoteException e) {
+ // binders may propagate some specific non-RemoteExceptions from the other side
+ // through the binder as well - we cannot allow those to crash the system server
+ Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
}
});
}
/**
* Runs the given function synchronously if currently connected, and returns the default value
- * if not currently connected or if any exception is thrown.
+ * if not currently connected or if any exception is thrown. Do not obtain any locks within the
+ * BlockingBinderRunner, or risk deadlock. The default value will be returned if there is no
+ * service connection when this is run, if a RemoteException occurs, or if the operation times
+ * out.
*
* @deprecated Using this function is an indication that your AIDL API is broken. Calls from
* system server to outside MUST be one-way, and so cannot return any result, and this
@@ -395,13 +418,16 @@ public class ServiceWatcher implements ServiceConnection {
public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
try {
return runOnHandlerBlocking(() -> {
- if (mBestService == null) {
+ if (mBinder == null) {
return defaultValue;
}
try {
- return runner.run(mBestService);
- } catch (RemoteException e) {
+ return runner.run(mBinder);
+ } catch (RuntimeException | RemoteException e) {
+ // binders may propagate some specific non-RemoteExceptions from the other side
+ // through the binder as well - we cannot allow those to crash the system server
+ Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
return defaultValue;
}
});
@@ -410,30 +436,6 @@ public class ServiceWatcher implements ServiceConnection {
}
}
- @Override
- public final void onServiceConnected(ComponentName component, IBinder binder) {
- runOnHandler(() -> {
- if (D) Log.d(mTag, component + " connected");
- mBestService = binder;
- onBind();
- });
- }
-
- @Override
- public final void onServiceDisconnected(ComponentName component) {
- runOnHandler(() -> {
- if (D) Log.d(mTag, component + " disconnected");
- mBestService = null;
- onUnbind();
- });
- }
-
- @Override
- public String toString() {
- ComponentName bestComponent = mBestComponent;
- return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
- }
-
private void runOnHandler(Runnable r) {
if (Looper.myLooper() == mHandler.getLooper()) {
r.run();
@@ -467,4 +469,8 @@ public class ServiceWatcher implements ServiceConnection {
}
}
}
+
+ private String getLogPrefix() {
+ return "[" + mIntent.getAction() + "]";
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 00c0b3e88517..5596b2fcb762 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -214,6 +214,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
@@ -751,67 +752,23 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * These are the currently running processes for which we have a ProcessInfo.
+ * Note: needs to be static since the permission checking call chain is static. This
+ * all probably should be refactored into a separate permission checking object.
+ */
+ @GuardedBy("sActiveProcessInfoSelfLocked")
+ static final SparseArray<ProcessInfo> sActiveProcessInfoSelfLocked = new SparseArray<>();
+
+ /**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
* <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
*/
final PidMap mPidsSelfLocked = new PidMap();
- final class PidMap {
+ static final class PidMap {
private final SparseArray<ProcessRecord> mPidMap = new SparseArray<>();
- /**
- * Puts the process record in the map.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- void put(ProcessRecord app) {
- synchronized (this) {
- mPidMap.put(app.pid, app);
- }
- mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
- }
-
- /**
- * Removes the process record from the map.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- void remove(ProcessRecord app) {
- boolean removed = false;
- synchronized (this) {
- final ProcessRecord existingApp = mPidMap.get(app.pid);
- if (existingApp != null && existingApp.startSeq == app.startSeq) {
- mPidMap.remove(app.pid);
- removed = true;
- }
- }
- if (removed) {
- mAtmInternal.onProcessUnMapped(app.pid);
- }
- }
-
- /**
- * Removes the process record from the map if it has a thread.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- boolean removeIfNoThread(ProcessRecord app) {
- boolean removed = false;
- synchronized (this) {
- final ProcessRecord existingApp = get(app.pid);
- if (existingApp != null && existingApp.startSeq == app.startSeq
- && app.thread == null) {
- mPidMap.remove(app.pid);
- removed = true;
- }
- }
- if (removed) {
- mAtmInternal.onProcessUnMapped(app.pid);
- }
- return removed;
- }
-
ProcessRecord get(int pid) {
return mPidMap.get(pid);
}
@@ -831,6 +788,82 @@ public class ActivityManagerService extends IActivityManager.Stub
int indexOfKey(int key) {
return mPidMap.indexOfKey(key);
}
+
+ void doAddInternal(ProcessRecord app) {
+ mPidMap.put(app.pid, app);
+ }
+
+ boolean doRemoveInternal(ProcessRecord app) {
+ final ProcessRecord existingApp = mPidMap.get(app.pid);
+ if (existingApp != null && existingApp.startSeq == app.startSeq) {
+ mPidMap.remove(app.pid);
+ return true;
+ }
+ return false;
+ }
+
+ boolean doRemoveIfNoThreadInternal(ProcessRecord app) {
+ if (app == null || app.thread != null) {
+ return false;
+ }
+ return doRemoveInternal(app);
+ }
+ }
+
+ /**
+ * Puts the process record in the map.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ void addPidLocked(ProcessRecord app) {
+ synchronized (mPidsSelfLocked) {
+ mPidsSelfLocked.doAddInternal(app);
+ }
+ synchronized (sActiveProcessInfoSelfLocked) {
+ if (app.processInfo != null) {
+ sActiveProcessInfoSelfLocked.put(app.pid, app.processInfo);
+ } else {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ }
+ mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
+ }
+
+ /**
+ * Removes the process record from the map.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ void removePidLocked(ProcessRecord app) {
+ final boolean removed;
+ synchronized (mPidsSelfLocked) {
+ removed = mPidsSelfLocked.doRemoveInternal(app);
+ }
+ if (removed) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ mAtmInternal.onProcessUnMapped(app.pid);
+ }
+ }
+
+ /**
+ * Removes the process record from the map if it doesn't have a thread.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ boolean removePidIfNoThread(ProcessRecord app) {
+ final boolean removed;
+ synchronized (mPidsSelfLocked) {
+ removed = mPidsSelfLocked.doRemoveIfNoThreadInternal(app);
+ }
+ if (removed) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ mAtmInternal.onProcessUnMapped(app.pid);
+ }
+ return removed;
}
/**
@@ -2061,7 +2094,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.getWindowProcessController().setPid(MY_PID);
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
- mPidsSelfLocked.put(app);
+ addPidLocked(app);
mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
}
@@ -4723,7 +4756,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
- boolean gone = mPidsSelfLocked.removeIfNoThread(app);
+ boolean gone = removePidIfNoThread(app);
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
@@ -4796,7 +4829,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// If there is already an app occupying that pid that hasn't been cleaned up
cleanUpApplicationRecordLocked(app, false, false, -1,
true /*replacingPid*/);
- mPidsSelfLocked.remove(app);
+ removePidLocked(app);
app = null;
}
} else {
@@ -5896,6 +5929,21 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ // If there is an explicit permission being checked, and this is coming from a process
+ // that has been denied access to that permission, then just deny. Ultimately this may
+ // not be quite right -- it means that even if the caller would have access for another
+ // reason (such as being the owner of the component it is trying to access), it would still
+ // fail. This also means the system and root uids would be able to deny themselves
+ // access to permissions, which... well okay. ¯\_(ツ)_/¯
+ if (permission != null) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ ProcessInfo procInfo = sActiveProcessInfoSelfLocked.get(pid);
+ if (procInfo != null && procInfo.deniedPermissions != null
+ && procInfo.deniedPermissions.contains(permission)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+ }
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
@@ -14367,7 +14415,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
- mPidsSelfLocked.remove(app);
+ removePidLocked(app);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index fa55701cd882..a03f0bb4e399 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -108,6 +108,21 @@ final class CoreSettingsObserver extends ContentObserver {
sDeviceConfigEntries.add(new DeviceConfigEntry(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_CONTROL,
WidgetFlags.KEY_ENABLE_CURSOR_CONTROL, boolean.class));
+ sDeviceConfigEntries.add(new DeviceConfigEntry(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_DELTA_HEIGHT,
+ WidgetFlags.KEY_INSERTION_HANDLE_DELTA_HEIGHT, int.class));
+ sDeviceConfigEntries.add(new DeviceConfigEntry(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.INSERTION_HANDLE_OPACITY,
+ WidgetFlags.KEY_INSERTION_HANDLE_OPACITY, int.class));
+ sDeviceConfigEntries.add(new DeviceConfigEntry(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_NEW_MAGNIFIER,
+ WidgetFlags.KEY_ENABLE_NEW_MAGNIFIER, boolean.class));
+ sDeviceConfigEntries.add(new DeviceConfigEntry(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ZOOM_FACTOR,
+ WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, float.class));
+ sDeviceConfigEntries.add(new DeviceConfigEntry(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
+ WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class));
// add other device configs here...
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4a8984524bb7..38cb501111ca 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1564,7 +1564,7 @@ public final class ProcessList {
long startTime = SystemClock.uptimeMillis();
if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
checkSlow(startTime, "startProcess: removing from pids map");
- mService.mPidsSelfLocked.remove(app);
+ mService.removePidLocked(app);
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
checkSlow(startTime, "startProcess: done removing from pids map");
app.setPid(0);
@@ -1609,10 +1609,28 @@ public final class ProcessList {
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
+
+ // Remove any gids needed if the process has been denied permissions.
+ // NOTE: eventually we should probably have the package manager pre-compute
+ // this for us?
+ if (app.processInfo != null && app.processInfo.deniedPermissions != null) {
+ for (int i = app.processInfo.deniedPermissions.size() - 1; i >= 0; i--) {
+ int[] denyGids = mService.mPackageManagerInt.getPermissionGids(
+ app.processInfo.deniedPermissions.valueAt(i), app.userId);
+ if (denyGids != null) {
+ for (int gid : denyGids) {
+ permGids = ArrayUtils.removeInt(permGids, gid);
+ }
+ }
+ }
+ }
+
int numGids = 3;
- if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE
+ || app.info.packageName.equals("com.android.externalstorage")) {
numGids++;
}
+
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
@@ -1626,8 +1644,14 @@ public final class ProcessList {
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;
+ if (app.info.packageName.equals("com.android.externalstorage")) {
+ // Allows access to 'unreliable' (USB OTG) volumes via SAF
+ gids[3] = Process.MEDIA_RW_GID;
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ gids[3] = Process.SDCARD_RW_GID;
+ }
}
// Replace any invalid GIDs
@@ -2311,7 +2335,7 @@ public final class ProcessList {
mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1,
true /*replacingPid*/);
}
- mService.mPidsSelfLocked.put(app);
+ mService.addPidLocked(app);
synchronized (mService.mPidsSelfLocked) {
if (!procAttached) {
Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
@@ -2492,7 +2516,7 @@ public final class ProcessList {
.pendingStart)) {
int pid = app.pid;
if (pid > 0) {
- mService.mPidsSelfLocked.remove(app);
+ mService.removePidLocked(app);
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
@@ -3945,4 +3969,3 @@ public final class ProcessList {
}
};
}
-
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 156466cee970..0e1e0f9f64f1 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -35,6 +35,7 @@ import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
@@ -84,6 +85,7 @@ class ProcessRecord implements WindowProcessListener {
private final ActivityManagerService mService; // where we came from
final ApplicationInfo info; // all about the first app in the process
+ final ProcessInfo processInfo; // if non-null, process-specific manifest info
final boolean isolated; // true if this is a special isolated process
final boolean appZygote; // true if this is forked from the app zygote
final int uid; // uid of process; may be different from 'info' if isolated
@@ -603,6 +605,13 @@ class ProcessRecord implements WindowProcessListener {
int _uid) {
mService = _service;
info = _info;
+ if (_service.mPackageManagerInt != null) {
+ ArrayMap<String, ProcessInfo> processes =
+ _service.mPackageManagerInt.getProcessesForUid(_uid);
+ processInfo = processes != null ? processes.get(_processName) : null;
+ } else {
+ processInfo = null;
+ }
isolated = _info.uid != _uid;
appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
&& UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 46972d90ce3b..8f6bd212da19 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -21,6 +21,7 @@ import static android.media.AudioManager.RINGER_MODE_NORMAL;
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import static android.media.AudioManager.STREAM_SYSTEM;
+import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
@@ -89,6 +90,7 @@ import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.AudioProductStrategy;
@@ -6774,6 +6776,7 @@ public class AudioService extends IAudioService.Stub
boolean requireValidProjection = false;
boolean requireCaptureAudioOrMediaOutputPerm = false;
+ boolean requireVoiceComunicationOutputPerm = false;
boolean requireModifyRouting = false;
if (hasFocusAccess || isVolumeController) {
@@ -6783,8 +6786,15 @@ public class AudioService extends IAudioService.Stub
requireModifyRouting |= true;
}
for (AudioMix mix : policyConfig.getMixes()) {
- // If mix is requesting a privileged capture
- if (mix.getRule().allowPrivilegedPlaybackCapture()) {
+ // If mix is trying to capture USAGE_VOICE_COMMUNICATION using playback capture
+ if (isVoiceCommunicationPlaybackCaptureMix(mix)) {
+ // then it must have CAPTURE_USAGE_VOICE_COMMUNICATION_OUTPUT permission
+ requireVoiceComunicationOutputPerm |= true;
+ }
+ // If mix is requesting privileged capture and is capturing at
+ // least one usage which is not USAGE_VOICE_COMMUNICATION.
+ if (mix.getRule().allowPrivilegedPlaybackCapture()
+ && isNonVoiceCommunicationCaptureMix(mix)) {
// then it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
requireCaptureAudioOrMediaOutputPerm |= true;
// and its format must be low quality enough
@@ -6812,6 +6822,14 @@ public class AudioService extends IAudioService.Stub
return false;
}
+ if (requireVoiceComunicationOutputPerm
+ && !callerHasPermission(
+ android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT)) {
+ Log.e(TAG, "Privileged audio capture for voice communication requires "
+ + "CAPTURE_VOICE_COMMUNICATION_OUTPUT system permission");
+ return false;
+ }
+
if (requireValidProjection && !canProjectAudio(projection)) {
return false;
}
@@ -6825,6 +6843,41 @@ public class AudioService extends IAudioService.Stub
return true;
}
+ /**
+ * Checks whether a given AudioMix is used for playback capture
+ * (has the ROUTE_FLAG_LOOP_BACK_RENDER flag) and has a matching
+ * criterion for USAGE_VOICE_COMMUNICATION.
+ */
+ private boolean isVoiceCommunicationPlaybackCaptureMix(AudioMix mix) {
+ if (mix.getRouteFlags() != mix.ROUTE_FLAG_LOOP_BACK_RENDER) {
+ return false;
+ }
+
+ for (AudioMixMatchCriterion criterion : mix.getRule().getCriteria()) {
+ if (criterion.getRule() == RULE_MATCH_ATTRIBUTE_USAGE
+ && criterion.getAudioAttributes().getUsage()
+ == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a given AudioMix has a matching
+ * criterion for a usage which is not USAGE_VOICE_COMMUNICATION.
+ */
+ private boolean isNonVoiceCommunicationCaptureMix(AudioMix mix) {
+ for (AudioMixMatchCriterion criterion : mix.getRule().getCriteria()) {
+ if (criterion.getRule() == RULE_MATCH_ATTRIBUTE_USAGE
+ && criterion.getAudioAttributes().getUsage()
+ != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean callerHasPermission(String permission) {
return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
@@ -6988,6 +7041,26 @@ public class AudioService extends IAudioService.Stub
}
}
+ /** see AudioPolicy.setUserIdDeviceAffinity() */
+ public int setUserIdDeviceAffinity(IAudioPolicyCallback pcb, int userId,
+ @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
+ if (DEBUG_AP) {
+ Log.d(TAG, "setUserIdDeviceAffinity for " + pcb.asBinder() + " user:" + userId);
+ }
+
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
+ if (app == null) {
+ return AudioManager.ERROR;
+ }
+ if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
+ return AudioManager.ERROR;
+ }
+ return app.setUserIdDeviceAffinities(userId, deviceTypes, deviceAddresses);
+ }
+ }
+
/** see AudioPolicy.removeUidDeviceAffinity() */
public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
if (DEBUG_AP) {
@@ -7003,6 +7076,22 @@ public class AudioService extends IAudioService.Stub
}
}
+ /** see AudioPolicy.removeUserIdDeviceAffinity() */
+ public int removeUserIdDeviceAffinity(IAudioPolicyCallback pcb, int userId) {
+ if (DEBUG_AP) {
+ Log.d(TAG, "removeUserIdDeviceAffinity for " + pcb.asBinder()
+ + " userId:" + userId);
+ }
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
+ if (app == null) {
+ return AudioManager.ERROR;
+ }
+ return app.removeUserIdDeviceAffinities(userId);
+ }
+ }
+
public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
+ " policy " + pcb.asBinder());
@@ -7238,6 +7327,9 @@ public class AudioService extends IAudioService.Stub
final HashMap<Integer, AudioDeviceArray> mUidDeviceAffinities =
new HashMap<Integer, AudioDeviceArray>();
+ final HashMap<Integer, AudioDeviceArray> mUserIdDeviceAffinities =
+ new HashMap<>();
+
final IMediaProjection mProjection;
private final class UnregisterOnStopCallback extends IMediaProjectionCallback.Stub {
public void onStop() {
@@ -7429,6 +7521,45 @@ public class AudioService extends IAudioService.Stub
return AudioManager.ERROR;
}
+ int setUserIdDeviceAffinities(int userId,
+ @NonNull int[] types, @NonNull String[] addresses) {
+ final Integer UserId = new Integer(userId);
+ int res;
+ if (mUserIdDeviceAffinities.remove(UserId) != null) {
+ final long identity = Binder.clearCallingIdentity();
+ res = AudioSystem.removeUserIdDeviceAffinities(UserId);
+ Binder.restoreCallingIdentity(identity);
+ if (res != AudioSystem.SUCCESS) {
+ Log.e(TAG, "AudioSystem. removeUserIdDeviceAffinities("
+ + UserId + ") failed, "
+ + " cannot call AudioSystem.setUserIdDeviceAffinities");
+ return AudioManager.ERROR;
+ }
+ }
+ final long identity = Binder.clearCallingIdentity();
+ res = AudioSystem.setUserIdDeviceAffinities(userId, types, addresses);
+ Binder.restoreCallingIdentity(identity);
+ if (res == AudioSystem.SUCCESS) {
+ mUserIdDeviceAffinities.put(UserId, new AudioDeviceArray(types, addresses));
+ return AudioManager.SUCCESS;
+ }
+ Log.e(TAG, "AudioSystem.setUserIdDeviceAffinities(" + userId + ") failed");
+ return AudioManager.ERROR;
+ }
+
+ int removeUserIdDeviceAffinities(int userId) {
+ if (mUserIdDeviceAffinities.remove(new Integer(userId)) != null) {
+ final long identity = Binder.clearCallingIdentity();
+ final int res = AudioSystem.removeUserIdDeviceAffinities(userId);
+ Binder.restoreCallingIdentity(identity);
+ if (res == AudioSystem.SUCCESS) {
+ return AudioManager.SUCCESS;
+ }
+ }
+ Log.e(TAG, "AudioSystem.removeUserIdDeviceAffinities failed");
+ return AudioManager.ERROR;
+ }
+
/** @return human readable debug informations summarizing the state of the object. */
public String toLogFriendlyString() {
String textDump = super.toLogFriendlyString();
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 299cb66faf0c..4fb6607a6b08 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -82,12 +82,14 @@ public class DefaultNetworkMetrics {
}
/**
- * Convert events in the ring buffer to protos and add to the given list
+ * Convert events in the ring buffer to a list of IpConnectivityEvent protos
*/
- public synchronized void listEventsAsProto(List<IpConnectivityEvent> out) {
+ public synchronized List<IpConnectivityEvent> listEventsAsProto() {
+ List<IpConnectivityEvent> list = new ArrayList<>();
for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
- out.add(IpConnectivityEventBuilder.toProto(ev));
+ list.add(IpConnectivityEventBuilder.toProto(ev));
}
+ return list;
}
public synchronized void flushEvents(List<IpConnectivityEvent> out) {
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 1337a93476bc..2c06d8230f13 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -244,9 +244,9 @@ final public class IpConnectivityMetrics extends SystemService {
private List<IpConnectivityEvent> listEventsAsProtos() {
final List<IpConnectivityEvent> events = IpConnectivityEventBuilder.toProto(getEvents());
if (mNetdListener != null) {
- mNetdListener.listAsProtos(events);
+ events.addAll(mNetdListener.listAsProtos());
}
- mDefaultNetworkMetrics.listEventsAsProto(events);
+ events.addAll(mDefaultNetworkMetrics.listEventsAsProto());
return events;
}
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 0d3105139b88..f2892cc81951 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -367,18 +367,20 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
}
/**
- * Convert events in the buffer to protos and add to the given list
+ * Convert events in the buffer to a list of IpConnectivityEvent protos
*/
- public synchronized void listAsProtos(List<IpConnectivityEvent> out) {
+ public synchronized List<IpConnectivityEvent> listAsProtos() {
+ List<IpConnectivityEvent> list = new ArrayList<>();
for (int i = 0; i < mNetworkMetrics.size(); i++) {
- out.add(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).connectMetrics));
+ list.add(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).connectMetrics));
}
for (int i = 0; i < mNetworkMetrics.size(); i++) {
- out.add(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).dnsMetrics));
+ list.add(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).dnsMetrics));
}
for (int i = 0; i < mWakeupStats.size(); i++) {
- out.add(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i)));
+ list.add(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i)));
}
+ return list;
}
private long getTransports(int netId) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 4796edf85279..e09cf6178981 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -20,6 +20,7 @@ import android.os.Environment;
import android.util.Slog;
import com.android.server.display.config.DisplayConfiguration;
+import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.XmlParser;
@@ -30,6 +31,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.math.BigDecimal;
import java.util.List;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -40,12 +42,15 @@ import javax.xml.datatype.DatatypeConfigurationException;
public class DisplayDeviceConfig {
private static final String TAG = "DisplayDeviceConfig";
+ public static final float HIGH_BRIGHTNESS_MODE_UNSUPPORTED = Float.NaN;
+
private static final String ETC_DIR = "etc";
private static final String DISPLAY_CONFIG_DIR = "displayconfig";
private static final String CONFIG_FILE_FORMAT = "display_%d.xml";
private float[] mNits;
private float[] mBrightness;
+ private BigDecimal mHighBrightnessModeStart;
private DisplayDeviceConfig() {
}
@@ -83,6 +88,18 @@ public class DisplayDeviceConfig {
return mBrightness;
}
+ /**
+ * Returns the point along the brightness value range {@link #getBrightness()} that
+ * high-brightness-mode begins. If high-brightness-mode is not supported, then
+ * Float.NaN is returned.
+ *
+ * @return The high brightness mode threshold, or Float.NaN if not supported.
+ */
+ public float getHighBrightnessModeStart() {
+ return mHighBrightnessModeStart != null
+ ? mHighBrightnessModeStart.floatValue() : HIGH_BRIGHTNESS_MODE_UNSUPPORTED;
+ }
+
private void initFromFile(File configFile) {
if (!configFile.exists()) {
// Display configuration files aren't required to exist.
@@ -104,7 +121,8 @@ public class DisplayDeviceConfig {
}
private void loadBrightnessMap(DisplayConfiguration config) {
- final List<Point> points = config.getScreenBrightnessMap().getPoint();
+ final NitsMap map = config.getScreenBrightnessMap();
+ final List<Point> points = map.getPoint();
final int size = points.size();
float[] nits = new float[size];
@@ -130,7 +148,9 @@ public class DisplayDeviceConfig {
}
++i;
}
+ final BigDecimal hbmStart = map.getHighBrightnessStart();
+ mHighBrightnessModeStart = hbmStart;
mNits = nits;
mBrightness = backlight;
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 1f17f9f1ca43..7e8fe3ae8428 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -41,8 +41,8 @@ import android.view.SurfaceControl;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
-import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -164,7 +164,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final class LocalDisplayDevice extends DisplayDevice {
private final long mPhysicalDisplayId;
- private final Light mBacklight;
+ private final LogicalLight mBacklight;
private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
private final boolean mIsInternal;
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
index 5c18f5880146..5161a77e4ede 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java
@@ -16,6 +16,10 @@
package com.android.server.incremental;
+import static android.content.pm.InstallationFile.FILE_TYPE_OBB;
+import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
+import static android.content.pm.PackageInstaller.LOCATION_MEDIA_OBB;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -171,7 +175,9 @@ public final class IncrementalManagerShellCommand extends ShellCommand {
session = packageInstaller.openSession(sessionId);
for (int i = 0; i < numFiles; i++) {
InstallationFile file = installationFiles.get(i);
- session.addFile(file.getName(), file.getSize(), file.getMetadata());
+ final int location = file.getFileType() == FILE_TYPE_OBB ? LOCATION_MEDIA_OBB
+ : LOCATION_DATA_APP;
+ session.addFile(location, file.getName(), file.getSize(), file.getMetadata(), null);
}
session.commit(localReceiver.getIntentSender());
final Intent result = localReceiver.getResult();
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index be20a445432b..521913a0c439 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -29,5 +29,8 @@ public abstract class LightsManager {
public static final int LIGHT_ID_WIFI = Type.WIFI;
public static final int LIGHT_ID_COUNT = Type.COUNT;
- public abstract Light getLight(int id);
+ /**
+ * Returns the logical light with the given type.
+ */
+ public abstract LogicalLight getLight(int id);
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 8e6e1d6502de..5683e6901a31 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -15,32 +15,223 @@
package com.android.server.lights;
+import android.Manifest;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
+import android.hardware.light.HwLight;
+import android.hardware.light.HwLightState;
+import android.hardware.light.ILights;
+import android.hardware.lights.ILightsManager;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Message;
+import android.os.Looper;
import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.Trace;
import android.provider.Settings;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.SurfaceControl;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
public class LightsService extends SystemService {
static final String TAG = "LightsService";
static final boolean DEBUG = false;
- final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+ private LightImpl[] mLights = null;
+ private SparseArray<LightImpl> mLightsById = null;
+
+ private ILights mVintfLights = null;
+
+ @VisibleForTesting
+ final LightsManagerBinderService mManagerService;
+
+ private Handler mH;
+
+ private final class LightsManagerBinderService extends ILightsManager.Stub {
+
+ private final class Session {
+ final IBinder mToken;
+ final SparseArray<LightState> mRequests = new SparseArray<>();
+
+ Session(IBinder token) {
+ mToken = token;
+ }
+
+ void setRequest(int lightId, LightState state) {
+ if (state != null) {
+ mRequests.put(lightId, state);
+ } else {
+ mRequests.remove(lightId);
+ }
+ }
+ }
+
+ @GuardedBy("LightsService.this")
+ private final List<Session> mSessions = new ArrayList<>();
+
+ /**
+ * Returns the lights available for apps to control on the device. Only lights that aren't
+ * reserved for system use are available to apps.
+ */
+ @Override
+ public List<Light> getLights() {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+ "getLights requires CONTROL_DEVICE_LIGHTS_PERMISSION");
+
+ synchronized (LightsService.this) {
+ final List<Light> lights = new ArrayList<Light>();
+ for (int i = 0; i < mLightsById.size(); i++) {
+ HwLight hwLight = mLightsById.valueAt(i).getHwLight();
+ if (!isSystemLight(hwLight)) {
+ lights.add(new Light(hwLight.id, hwLight.ordinal, hwLight.type));
+ }
+ }
+ return lights;
+ }
+ }
+
+ /**
+ * Updates the set of light requests for {@param token} with additions and removals from
+ * {@param lightIds} and {@param lightStates}.
+ *
+ * <p>Null values mean that the request should be removed, and the light turned off if it
+ * is not being used by anything else.
+ */
+ @Override
+ public void setLightStates(IBinder token, int[] lightIds, LightState[] lightStates) {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+ "setLightStates requires CONTROL_DEVICE_LIGHTS permission");
+ Preconditions.checkState(lightIds.length == lightStates.length);
+
+ synchronized (LightsService.this) {
+ Session session = getSessionLocked(Preconditions.checkNotNull(token));
+ Preconditions.checkState(session != null, "not registered");
+
+ checkRequestIsValid(lightIds);
+
+ for (int i = 0; i < lightIds.length; i++) {
+ session.setRequest(lightIds[i], lightStates[i]);
+ }
+ invalidateLightStatesLocked();
+ }
+ }
+
+ @Override
+ public @Nullable LightState getLightState(int lightId) {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+ "getLightState(@TestApi) requires CONTROL_DEVICE_LIGHTS permission");
+
+ synchronized (LightsService.this) {
+ final LightImpl light = mLightsById.get(lightId);
+ if (light == null || isSystemLight(light.getHwLight())) {
+ throw new IllegalArgumentException("Invalid light: " + lightId);
+ }
+ return new LightState(light.getColor());
+ }
+ }
+
+ @Override
+ public void openSession(IBinder token) {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+ "openSession requires CONTROL_DEVICE_LIGHTS permission");
+ Preconditions.checkNotNull(token);
+
+ synchronized (LightsService.this) {
+ Preconditions.checkState(getSessionLocked(token) == null, "already registered");
+ try {
+ token.linkToDeath(() -> closeSessionInternal(token), 0);
+ mSessions.add(new Session(token));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't open session, client already died" , e);
+ throw new IllegalArgumentException("Client is already dead.");
+ }
+ }
+ }
+
+ @Override
+ public void closeSession(IBinder token) {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS,
+ "closeSession requires CONTROL_DEVICE_LIGHTS permission");
+ Preconditions.checkNotNull(token);
+ closeSessionInternal(token);
+ }
+
+ private void closeSessionInternal(IBinder token) {
+ synchronized (LightsService.this) {
+ final Session session = getSessionLocked(token);
+ if (session != null) {
+ mSessions.remove(session);
+ invalidateLightStatesLocked();
+ }
+ }
+ }
+
+ private void checkRequestIsValid(int[] lightIds) {
+ for (int i = 0; i < lightIds.length; i++) {
+ final LightImpl light = mLightsById.get(lightIds[i]);
+ final HwLight hwLight = light.getHwLight();
+ Preconditions.checkState(light != null && !isSystemLight(hwLight),
+ "invalid lightId " + hwLight.id);
+ }
+ }
+
+ /**
+ * Apply light state requests for all light IDs.
+ *
+ * <p>In case of conflict, the session that started earliest wins.
+ */
+ private void invalidateLightStatesLocked() {
+ final Map<Integer, LightState> states = new HashMap<>();
+ for (int i = mSessions.size() - 1; i >= 0; i--) {
+ SparseArray<LightState> requests = mSessions.get(i).mRequests;
+ for (int j = 0; j < requests.size(); j++) {
+ states.put(requests.keyAt(j), requests.valueAt(j));
+ }
+ }
+ for (int i = 0; i < mLightsById.size(); i++) {
+ LightImpl light = mLightsById.valueAt(i);
+ HwLight hwLight = light.getHwLight();
+ if (!isSystemLight(hwLight)) {
+ LightState state = states.get(hwLight.id);
+ if (state != null) {
+ light.setColor(state.getColor());
+ } else {
+ light.turnOff();
+ }
+ }
+ }
+ }
- private final class LightImpl extends Light {
+ private @Nullable Session getSessionLocked(IBinder token) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ if (token.equals(mSessions.get(i).mToken)) {
+ return mSessions.get(i);
+ }
+ }
+ return null;
+ }
+ }
+ private final class LightImpl extends LogicalLight {
private final IBinder mDisplayToken;
private final int mSurfaceControlMaximumBrightness;
- private LightImpl(Context context, int id) {
- mId = id;
+ private LightImpl(Context context, HwLight hwLight) {
+ mHwLight = hwLight;
mDisplayToken = SurfaceControl.getInternalDisplayToken();
final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport(
mDisplayToken);
@@ -78,8 +269,8 @@ public class LightsService extends SystemService {
synchronized (this) {
// LOW_PERSISTENCE cannot be manually set
if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
- Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
- ": brightness=0x" + Integer.toHexString(brightness));
+ Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
+ + ": brightness=0x" + Integer.toHexString(brightness));
return;
}
// Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
@@ -138,7 +329,7 @@ public class LightsService extends SystemService {
setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
BRIGHTNESS_MODE_USER);
mColor = 0;
- mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
+ mH.postDelayed(this::stopFlashing, onMS);
}
}
}
@@ -185,8 +376,10 @@ public class LightsService extends SystemService {
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
- if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
- + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+ if (DEBUG) {
+ Slog.v(TAG, "setLight #" + mHwLight.id + ": color=#"
+ + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+ }
mInitialized = true;
mLastColor = mColor;
mColor = color;
@@ -194,10 +387,31 @@ public class LightsService extends SystemService {
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
- + Integer.toHexString(color) + ")");
+ setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
+ }
+ }
+
+ private void setLightUnchecked(int color, int mode, int onMS, int offMS,
+ int brightnessMode) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
+ + Integer.toHexString(color) + ")");
+ if (mVintfLights != null) {
+ HwLightState lightState = new HwLightState();
+ lightState.color = color;
+ lightState.flashMode = (byte) mode;
+ lightState.flashOnMs = onMS;
+ lightState.flashOffMs = offMS;
+ lightState.brightnessMode = (byte) brightnessMode;
try {
- setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
+ mVintfLights.setLightState(mHwLight.id, lightState);
+ } catch (RemoteException | UnsupportedOperationException ex) {
+ Slog.e(TAG, "Failed issuing setLightState", ex);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ } else {
+ try {
+ setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -208,7 +422,15 @@ public class LightsService extends SystemService {
return mVrModeEnabled && mUseLowPersistenceForVR;
}
- private int mId;
+ private HwLight getHwLight() {
+ return mHwLight;
+ }
+
+ private int getColor() {
+ return mColor;
+ }
+
+ private HwLight mHwLight;
private int mColor;
private int mMode;
private int mOnMS;
@@ -223,16 +445,59 @@ public class LightsService extends SystemService {
}
public LightsService(Context context) {
+ this(context,
+ ILights.Stub.asInterface(
+ ServiceManager.getService("android.hardware.light.ILights/default")),
+ Looper.myLooper());
+ }
+
+ @VisibleForTesting
+ LightsService(Context context, ILights service, Looper looper) {
super(context);
+ mH = new Handler(looper);
+ mVintfLights = service;
+ mManagerService = new LightsManagerBinderService();
+ populateAvailableLights(context);
+ }
- for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
- mLights[i] = new LightImpl(context, i);
+ private void populateAvailableLights(Context context) {
+ mLights = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+ mLightsById = new SparseArray<>();
+
+ if (mVintfLights != null) {
+ try {
+ for (HwLight availableLight : mVintfLights.getLights()) {
+ LightImpl light = new LightImpl(context, availableLight);
+ int type = (int) availableLight.type;
+ if (0 <= type && type < mLights.length && mLights[type] == null) {
+ mLights[type] = light;
+ }
+ mLightsById.put(availableLight.id, light);
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to get lights for initialization", ex);
+ }
+ }
+
+ // In the case where only the old HAL is available, all lights will be initialized here
+ for (int i = 0; i < mLights.length; i++) {
+ if (mLights[i] == null) {
+ // The ordinal can be anything if there is only 1 light of each type. Set it to 1.
+ HwLight light = new HwLight();
+ light.id = (byte) i;
+ light.ordinal = 1;
+ light.type = (byte) i;
+
+ mLights[i] = new LightImpl(context, light);
+ mLightsById.put(i, mLights[i]);
+ }
}
}
@Override
public void onStart() {
publishLocalService(LightsManager.class, mService);
+ publishBinderService(Context.LIGHTS_SERVICE, mManagerService);
}
@Override
@@ -249,22 +514,25 @@ public class LightsService extends SystemService {
private final LightsManager mService = new LightsManager() {
@Override
- public Light getLight(int id) {
- if (0 <= id && id < LIGHT_ID_COUNT) {
- return mLights[id];
+ public LogicalLight getLight(int lightType) {
+ if (mLights != null && 0 <= lightType && lightType < mLights.length) {
+ return mLights[lightType];
} else {
return null;
}
}
};
- private Handler mH = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- LightImpl light = (LightImpl)msg.obj;
- light.stopFlashing();
- }
- };
+ /**
+ * Returns whether a light is system-use-only or should be accessible to
+ * applications using the {@link android.hardware.lights.LightsManager} API.
+ */
+ private static boolean isSystemLight(HwLight light) {
+ // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system
+ // lights. Newly added lights will be made available via the
+ // LightsManager API.
+ return 0 <= light.type && light.type < LightsManager.LIGHT_ID_COUNT;
+ }
static native void setLight_native(int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/LogicalLight.java
index 998c7c66b504..33dfbb4eea48 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/LogicalLight.java
@@ -19,9 +19,24 @@ package com.android.server.lights;
import android.hardware.light.V2_0.Brightness;
import android.hardware.light.V2_0.Flash;
-public abstract class Light {
+/**
+ * Allow control over a logical light of a given type. The mapping of logical lights to physical
+ * lights is HAL implementation-dependent.
+ */
+public abstract class LogicalLight {
+ /**
+ * Keep the light steady on or off.
+ */
public static final int LIGHT_FLASH_NONE = Flash.NONE;
+
+ /**
+ * Flash the light at specified rate.
+ */
public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
+
+ /**
+ * Flash the light using hardware assist.
+ */
public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
/**
@@ -55,10 +70,33 @@ public abstract class Light {
*/
public abstract void setBrightnessFloat(float brightness);
+ /**
+ * Set the color of a light.
+ */
public abstract void setColor(int color);
+
+ /**
+ * Set the color of a light and control flashing.
+ */
public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+
+ /**
+ * Pulses the light.
+ */
public abstract void pulse();
+
+ /**
+ * Pulses the light with a specified color for a specified duration.
+ */
public abstract void pulse(int color, int onMS);
+
+ /**
+ * Turns off the light.
+ */
public abstract void turnOff();
+
+ /**
+ * Set the VR mode of a display.
+ */
public abstract void setVrMode(boolean enabled);
}
diff --git a/services/core/java/com/android/server/lights/OWNERS b/services/core/java/com/android/server/lights/OWNERS
index c7c6d5658d1d..0e795b9a5ef8 100644
--- a/services/core/java/com/android/server/lights/OWNERS
+++ b/services/core/java/com/android/server/lights/OWNERS
@@ -1,2 +1,3 @@
michaelwr@google.com
-dangittik@google.com
+santoscordon@google.com
+flc@google.com
diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
deleted file mode 100644
index 80ab7903cef7..000000000000
--- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.location;
-
-import android.content.Context;
-import android.hardware.location.ActivityRecognitionHardware;
-import android.hardware.location.IActivityRecognitionHardwareClient;
-import android.hardware.location.IActivityRecognitionHardwareWatcher;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.server.FgThread;
-import com.android.server.ServiceWatcher;
-
-/**
- * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
- *
- * @hide
- */
-public class ActivityRecognitionProxy {
-
- private static final String TAG = "ActivityRecognitionProxy";
-
- /**
- * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
- *
- * @return An instance of the proxy if it could be bound, null otherwise.
- */
- public static ActivityRecognitionProxy createAndBind(
- Context context,
- boolean activityRecognitionHardwareIsSupported,
- ActivityRecognitionHardware activityRecognitionHardware,
- int overlaySwitchResId,
- int defaultServicePackageNameResId,
- int initialPackageNameResId) {
- ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy(
- context,
- activityRecognitionHardwareIsSupported,
- activityRecognitionHardware,
- overlaySwitchResId,
- defaultServicePackageNameResId,
- initialPackageNameResId);
-
- if (activityRecognitionProxy.mServiceWatcher.start()) {
- return activityRecognitionProxy;
- } else {
- return null;
- }
- }
-
- private final ServiceWatcher mServiceWatcher;
- private final boolean mIsSupported;
- private final ActivityRecognitionHardware mInstance;
-
- private ActivityRecognitionProxy(
- Context context,
- boolean activityRecognitionHardwareIsSupported,
- ActivityRecognitionHardware activityRecognitionHardware,
- int overlaySwitchResId,
- int defaultServicePackageNameResId,
- int initialPackageNameResId) {
- mIsSupported = activityRecognitionHardwareIsSupported;
- mInstance = activityRecognitionHardware;
-
- mServiceWatcher = new ServiceWatcher(
- context,
- TAG,
- "com.android.location.service.ActivityRecognitionProvider",
- overlaySwitchResId,
- defaultServicePackageNameResId,
- initialPackageNameResId,
- FgThread.getHandler()) {
- @Override
- protected void onBind() {
- runOnBinder(ActivityRecognitionProxy.this::initializeService);
- }
- };
- }
-
- private void initializeService(IBinder binder) {
- try {
- String descriptor = binder.getInterfaceDescriptor();
-
- if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(
- descriptor)) {
- IActivityRecognitionHardwareWatcher watcher =
- IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
- if (mInstance != null) {
- watcher.onInstanceChanged(mInstance);
- }
- } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
- .equals(descriptor)) {
- IActivityRecognitionHardwareClient client =
- IActivityRecognitionHardwareClient.Stub.asInterface(binder);
- client.onAvailabilityChanged(mIsSupported, mInstance);
- } else {
- Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
- }
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- }
-}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 45d9bae23e26..bb96e985cf53 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -33,6 +33,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -449,6 +450,28 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
}
}
+ /**
+ * Dump debugging info as ClientBrokerProto
+ *
+ * If the output belongs to a sub message, the caller is responsible for wrapping this function
+ * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
+ *
+ * @param proto the ProtoOutputStream to write to
+ */
+ void dump(ProtoOutputStream proto) {
+ proto.write(ClientBrokerProto.ENDPOINT_ID, getHostEndPointId());
+ proto.write(ClientBrokerProto.ATTACHED_CONTEXT_HUB_ID, getAttachedContextHubId());
+ proto.write(ClientBrokerProto.PACKAGE, mPackage);
+ if (mPendingIntentRequest.isValid()) {
+ proto.write(ClientBrokerProto.PENDING_INTENT_REQUEST_VALID, true);
+ proto.write(ClientBrokerProto.NANO_APP_ID, mPendingIntentRequest.getNanoAppId());
+ }
+ proto.write(ClientBrokerProto.HAS_PENDING_INTENT, mPendingIntentRequest.hasPendingIntent());
+ proto.write(ClientBrokerProto.PENDING_INTENT_CANCELLED, isPendingIntentCancelled());
+ proto.write(ClientBrokerProto.REGISTERED, mRegistered);
+
+ }
+
@Override
public String toString() {
String out = "[ContextHubClient ";
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index 46db8dc5dd77..0f70bb8bc840 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -27,10 +27,13 @@ import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.RemoteException;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Calendar;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
@@ -45,6 +48,11 @@ import java.util.function.Consumer;
private static final String TAG = "ContextHubClientManager";
/*
+ * The DateFormat for printing RegistrationRecord.
+ */
+ private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS");
+
+ /*
* The maximum host endpoint ID value that a client can be assigned.
*/
private static final int MAX_CLIENT_ID = 0x7fff;
@@ -123,24 +131,24 @@ import java.util.function.Consumer;
private class RegistrationRecord {
private final String mBroker;
private final int mAction;
- private final String mDate;
+ private final long mTimestamp;
RegistrationRecord(String broker, @Action int action) {
mBroker = broker;
mAction = action;
- Calendar instance = Calendar.getInstance();
- mDate = String.format("%02d", instance.get(Calendar.MONTH) + 1) // Jan == 0
- + "/" + String.format("%02d", instance.get(Calendar.DAY_OF_MONTH))
- + " " + String.format("%02d", instance.get(Calendar.HOUR_OF_DAY))
- + ":" + String.format("%02d", instance.get(Calendar.MINUTE))
- + ":" + String.format("%02d", instance.get(Calendar.SECOND))
- + "." + String.format("%03d", instance.get(Calendar.MILLISECOND));
+ mTimestamp = System.currentTimeMillis();
+ }
+
+ void dump(ProtoOutputStream proto) {
+ proto.write(ClientManagerProto.RegistrationRecord.TIMESTAMP_MS, mTimestamp);
+ proto.write(ClientManagerProto.RegistrationRecord.ACTION, mAction);
+ proto.write(ClientManagerProto.RegistrationRecord.BROKER, mBroker);
}
@Override
public String toString() {
String out = "";
- out += mDate + " ";
+ out += DATE_FORMAT.format(new Date(mTimestamp)) + " ";
out += mAction == ACTION_REGISTERED ? "+ " : "- ";
out += mBroker;
if (mAction == ACTION_CANCELLED) {
@@ -376,6 +384,28 @@ import java.util.function.Consumer;
return null;
}
+ /**
+ * Dump debugging info as ClientManagerProto
+ *
+ * If the output belongs to a sub message, the caller is responsible for wrapping this function
+ * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
+ *
+ * @param proto the ProtoOutputStream to write to
+ */
+ void dump(ProtoOutputStream proto) {
+ for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+ long token = proto.start(ClientManagerProto.CLIENT_BROKERS);
+ broker.dump(proto);
+ proto.end(token);
+ }
+ Iterator<RegistrationRecord> it = mRegistrationRecordDeque.descendingIterator();
+ while (it.hasNext()) {
+ long token = proto.start(ClientManagerProto.REGISTRATION_RECORDS);
+ it.next().dump(proto);
+ proto.end(token);
+ }
+ }
+
@Override
public String toString() {
String out = "";
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index 787a8007920d..e79eddf247cb 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -43,6 +43,7 @@ import android.hardware.location.NanoAppState;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.util.DumpUtils;
@@ -782,6 +783,13 @@ public class ContextHubService extends IContextHubService.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ for (String arg : args) {
+ if ("--proto".equals(arg)) {
+ dump(new ProtoOutputStream(fd));
+ return;
+ }
+ }
+
pw.println("Dumping ContextHub Service");
pw.println("");
@@ -802,6 +810,20 @@ public class ContextHubService extends IContextHubService.Stub {
// dump eventLog
}
+ private void dump(ProtoOutputStream proto) {
+ mContextHubIdToInfoMap.values().forEach(hubInfo -> {
+ long token = proto.start(ContextHubServiceProto.CONTEXT_HUB_INFO);
+ hubInfo.dump(proto);
+ proto.end(token);
+ });
+
+ long token = proto.start(ContextHubServiceProto.CLIENT_MANAGER);
+ mClientManager.dump(proto);
+ proto.end(token);
+
+ proto.flush();
+ }
+
private void checkPermissions() {
ContextHubServiceUtil.checkPermissions(mContext);
}
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index e6f0ed9d14b0..536f95a40431 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.annotation.Nullable;
import android.content.Context;
import android.location.Address;
import android.location.GeocoderParams;
@@ -28,40 +29,38 @@ import java.util.List;
/**
* Proxy for IGeocodeProvider implementations.
+ *
+ * @hide
*/
public class GeocoderProxy {
- private static final String TAG = "GeocoderProxy";
private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
- private final ServiceWatcher mServiceWatcher;
-
- public static GeocoderProxy createAndBind(Context context,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId) {
- GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId);
- if (proxy.bind()) {
+ /**
+ * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+ * null.
+ */
+ @Nullable
+ public static GeocoderProxy createAndRegister(Context context) {
+ GeocoderProxy proxy = new GeocoderProxy(context);
+ if (proxy.register()) {
return proxy;
} else {
return null;
}
}
- private GeocoderProxy(Context context,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId) {
- mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId,
- BackgroundThread.getHandler());
- }
+ private final ServiceWatcher mServiceWatcher;
- private boolean bind() {
- return mServiceWatcher.start();
+ private GeocoderProxy(Context context) {
+ mServiceWatcher = new ServiceWatcher(context, BackgroundThread.getHandler(), SERVICE_ACTION,
+ null, null,
+ com.android.internal.R.bool.config_enableGeocoderOverlay,
+ com.android.internal.R.string.config_geocoderProviderPackageName);
}
- public String getConnectedPackageName() {
- return mServiceWatcher.getCurrentPackageName();
+ private boolean register() {
+ return mServiceWatcher.register();
}
public String getFromLocation(double latitude, double longitude, int maxResults,
@@ -83,5 +82,4 @@ public class GeocoderProxy {
maxResults, params, addrs);
}, "Service not Available");
}
-
}
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index ce93661a8810..f006fb177382 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.hardware.location.GeofenceHardwareService;
import android.hardware.location.IGeofenceHardware;
-import android.location.IFusedGeofenceHardware;
import android.location.IGeofenceProvider;
import android.location.IGpsGeofenceHardware;
import android.os.IBinder;
@@ -33,6 +32,8 @@ import android.util.Log;
import com.android.server.FgThread;
import com.android.server.ServiceWatcher;
+import java.util.Objects;
+
/**
* @hide
*/
@@ -41,64 +42,41 @@ public final class GeofenceProxy {
private static final String TAG = "GeofenceProxy";
private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider";
- private final Context mContext;
- private final ServiceWatcher mServiceWatcher;
-
- @Nullable
- private final IGpsGeofenceHardware mGpsGeofenceHardware;
@Nullable
- private final IFusedGeofenceHardware mFusedGeofenceHardware;
-
- private volatile IGeofenceHardware mGeofenceHardware;
-
- private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> {
- IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
- try {
- provider.setGeofenceHardware(mGeofenceHardware);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- };
-
- public static GeofenceProxy createAndBind(Context context,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
- @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
- GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence,
- fusedGeofenceHardware);
-
- if (proxy.bind()) {
+ public static GeofenceProxy createAndBind(Context context, IGpsGeofenceHardware gpsGeofence) {
+ GeofenceProxy proxy = new GeofenceProxy(context, gpsGeofence);
+ if (proxy.register(context)) {
return proxy;
} else {
return null;
}
}
- private GeofenceProxy(Context context,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
- @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
- mContext = context;
- mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId,
- FgThread.getHandler()) {
- @Override
- protected void onBind() {
- runOnBinder(mUpdateGeofenceHardware);
- }
- };
+ private final IGpsGeofenceHardware mGpsGeofenceHardware;
+ private final ServiceWatcher mServiceWatcher;
- mGpsGeofenceHardware = gpsGeofence;
- mFusedGeofenceHardware = fusedGeofenceHardware;
+ private volatile IGeofenceHardware mGeofenceHardware;
+
+ private GeofenceProxy(Context context, IGpsGeofenceHardware gpsGeofence) {
+ mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence);
+ mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), SERVICE_ACTION,
+ this::updateGeofenceHardware, null,
+ com.android.internal.R.bool.config_enableGeofenceOverlay,
+ com.android.internal.R.string.config_geofenceProviderPackageName);
mGeofenceHardware = null;
}
- private boolean bind() {
- if (mServiceWatcher.start()) {
- mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
- new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE,
+ private void updateGeofenceHardware(IBinder binder) throws RemoteException {
+ IGeofenceProvider.Stub.asInterface(binder).setGeofenceHardware(mGeofenceHardware);
+ }
+
+ private boolean register(Context context) {
+ if (mServiceWatcher.register()) {
+ context.bindServiceAsUser(
+ new Intent(context, GeofenceHardwareService.class),
+ new GeofenceProxyServiceConnection(),
+ Context.BIND_AUTO_CREATE,
UserHandle.SYSTEM);
return true;
}
@@ -113,24 +91,18 @@ public final class GeofenceProxy {
IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service);
try {
- if (mGpsGeofenceHardware != null) {
- geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
- }
- if (mFusedGeofenceHardware != null) {
- geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
- }
-
+ geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
mGeofenceHardware = geofenceHardware;
- mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
- } catch (Exception e) {
- Log.w(TAG, e);
+ mServiceWatcher.runOnBinder(GeofenceProxy.this::updateGeofenceHardware);
+ } catch (RemoteException e) {
+ Log.w(TAG, "unable to initialize geofence hardware", e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mGeofenceHardware = null;
- mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
+ mServiceWatcher.runOnBinder(GeofenceProxy.this::updateGeofenceHardware);
}
}
}
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
new file mode 100644
index 000000000000..9d9852ba5da3
--- /dev/null
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.location.ActivityRecognitionHardware;
+import android.hardware.location.IActivityRecognitionHardwareClient;
+import android.hardware.location.IActivityRecognitionHardwareWatcher;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.server.FgThread;
+import com.android.server.ServiceWatcher;
+
+/**
+ * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
+ *
+ * @hide
+ */
+public class HardwareActivityRecognitionProxy {
+
+ private static final String TAG = "ARProxy";
+ private static final String SERVICE_ACTION =
+ "com.android.location.service.ActivityRecognitionProvider";
+
+ /**
+ * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+ * null.
+ */
+ @Nullable
+ public static HardwareActivityRecognitionProxy createAndRegister(Context context) {
+ HardwareActivityRecognitionProxy arProxy = new HardwareActivityRecognitionProxy(context);
+ if (arProxy.register()) {
+ return arProxy;
+ } else {
+ return null;
+ }
+ }
+
+ private final boolean mIsSupported;
+ private final ActivityRecognitionHardware mInstance;
+
+ private final ServiceWatcher mServiceWatcher;
+
+ private HardwareActivityRecognitionProxy(Context context) {
+ mIsSupported = ActivityRecognitionHardware.isSupported();
+ if (mIsSupported) {
+ mInstance = ActivityRecognitionHardware.getInstance(context);
+ } else {
+ mInstance = null;
+ }
+
+ mServiceWatcher = new ServiceWatcher(context,
+ FgThread.getHandler(),
+ SERVICE_ACTION,
+ this::onBind,
+ null,
+ com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
+ com.android.internal.R.string.config_activityRecognitionHardwarePackageName);
+ }
+
+ private boolean register() {
+ return mServiceWatcher.register();
+ }
+
+ private void onBind(IBinder binder) throws RemoteException {
+ String descriptor = binder.getInterfaceDescriptor();
+
+ if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
+ IActivityRecognitionHardwareWatcher watcher =
+ IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
+ if (mInstance != null) {
+ watcher.onInstanceChanged(mInstance);
+ }
+ } else if (IActivityRecognitionHardwareClient.class.getCanonicalName().equals(descriptor)) {
+ IActivityRecognitionHardwareClient client =
+ IActivityRecognitionHardwareClient.Stub.asInterface(binder);
+ client.onAvailabilityChanged(mIsSupported, mInstance);
+ } else {
+ Log.e(TAG, "Unknown descriptor: " + descriptor);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 8a149afa6238..805b018a8f45 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -19,12 +19,11 @@ package com.android.server.location;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArraySet;
@@ -35,7 +34,6 @@ import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.FgThread;
-import com.android.server.LocationManagerService;
import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
@@ -49,17 +47,31 @@ import java.util.List;
public class LocationProviderProxy extends AbstractLocationProvider {
private static final String TAG = "LocationProviderProxy";
- private static final boolean D = LocationManagerService.D;
private static final int MAX_ADDITIONAL_PACKAGES = 2;
+ /**
+ * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+ * null.
+ */
+ @Nullable
+ public static LocationProviderProxy createAndRegister(Context context, String action,
+ int enableOverlayResId, int nonOverlayPackageResId) {
+ LocationProviderProxy proxy = new LocationProviderProxy(context, action, enableOverlayResId,
+ nonOverlayPackageResId);
+ if (proxy.register()) {
+ return proxy;
+ } else {
+ return null;
+ }
+ }
+
private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
// executed on binder thread
@Override
public void onSetAdditionalProviderPackages(List<String> packageNames) {
- int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()) + 1;
+ int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size());
ArraySet<String> allPackages = new ArraySet<>(maxCount);
- allPackages.add(mServiceWatcher.getCurrentPackageName());
for (String packageName : packageNames) {
if (packageNames.size() >= maxCount) {
return;
@@ -74,6 +86,12 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
}
+ // add the binder package
+ ComponentName service = mServiceWatcher.getBoundService().component;
+ if (service != null) {
+ allPackages.add(service.getPackageName());
+ }
+
setPackageNames(allPackages);
}
@@ -100,63 +118,39 @@ public class LocationProviderProxy extends AbstractLocationProvider {
@Nullable private ProviderRequest mRequest;
- /**
- * Creates a new LocationProviderProxy and immediately begins binding to the best applicable
- * service.
- */
- @Nullable
- public static LocationProviderProxy createAndBind(Context context, String action,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId) {
- LocationProviderProxy proxy = new LocationProviderProxy(context, FgThread.getHandler(),
- action, overlaySwitchResId, defaultServicePackageNameResId,
- initialPackageNamesResId);
- if (proxy.bind()) {
- return proxy;
- } else {
- return null;
- }
- }
-
- private LocationProviderProxy(Context context, Handler handler, String action,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId) {
- super(context, new HandlerExecutor(handler), Collections.emptySet());
+ private LocationProviderProxy(Context context, String action, int enableOverlayResId,
+ int nonOverlayPackageResId) {
+ super(context, FgThread.getExecutor());
- mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, handler) {
-
- @Override
- protected void onBind() {
- runOnBinder(LocationProviderProxy.this::initializeService);
- }
-
- @Override
- protected void onUnbind() {
- setState(State.EMPTY_STATE);
- }
- };
+ mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), action, this::onBind,
+ this::onUnbind, enableOverlayResId, nonOverlayPackageResId);
mRequest = null;
}
- private boolean bind() {
- return mServiceWatcher.start();
+ private boolean register() {
+ return mServiceWatcher.register();
}
- private void initializeService(IBinder binder) throws RemoteException {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
+ private void onBind(IBinder binder) throws RemoteException {
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
- setPackageNames(Collections.singleton(mServiceWatcher.getCurrentPackageName()));
+ ComponentName service = mServiceWatcher.getBoundService().component;
+ if (service != null) {
+ setPackageNames(Collections.singleton(service.getPackageName()));
+ }
- service.setLocationProviderManager(mManager);
+ provider.setLocationProviderManager(mManager);
if (mRequest != null) {
- service.setRequest(mRequest, mRequest.workSource);
+ provider.setRequest(mRequest, mRequest.workSource);
}
}
+ private void onUnbind() {
+ setState(State.EMPTY_STATE);
+ }
+
@Override
public void onSetRequest(ProviderRequest request) {
mServiceWatcher.runOnBinder(binder -> {
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index 45c833498ac7..b191338970e9 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -92,7 +92,7 @@ public class LocationRequestStatistics {
/**
* A key that holds both package and provider names.
*/
- public static class PackageProviderKey {
+ public static class PackageProviderKey implements Comparable<PackageProviderKey> {
/**
* Name of package requesting location.
*/
@@ -108,6 +108,16 @@ public class LocationRequestStatistics {
}
@Override
+ public int compareTo(PackageProviderKey other) {
+ final int providerCompare = providerName.compareTo(other.providerName);
+ if (providerCompare != 0) {
+ return providerCompare;
+ } else {
+ return packageName.compareTo(other.packageName);
+ }
+ }
+
+ @Override
public boolean equals(Object other) {
if (!(other instanceof PackageProviderKey)) {
return false;
@@ -211,7 +221,7 @@ public class LocationRequestStatistics {
void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
StringBuilder s = new StringBuilder();
long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
- s.append("At ").append(TimeUtils.formatForLogging(systemTimeMillis)).append(": ")
+ s.append("At ").append(TimeUtils.logTimeOfDay(systemTimeMillis)).append(": ")
.append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
.append(String.format("%7s", mProviderName)).append(" request from ")
.append(mPackageName);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4a6fcdf73b90..a6ad57a7ae3a 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -103,6 +103,7 @@ public class MediaSessionService extends SystemService implements Monitor {
private static final int WAKELOCK_TIMEOUT = 5000;
private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
+ private static final int SESSION_CREATION_LIMIT_PER_UID = 100;
private final Context mContext;
private final SessionManagerImpl mSessionManagerImpl;
@@ -428,6 +429,18 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.d(TAG, "Destroying " + session);
}
FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+
+ if (user != null) {
+ final int uid = session.getUid();
+ final int sessionCount = user.mUidToSessionCount.get(uid, 0);
+ if (sessionCount <= 0) {
+ Log.w(TAG, "destroySessionLocked: sessionCount should be positive. "
+ + "sessionCount=" + sessionCount);
+ } else {
+ user.mUidToSessionCount.put(uid, sessionCount - 1);
+ }
+ }
+
if (mGlobalPrioritySession == session) {
mGlobalPrioritySession = null;
if (session.isActive() && user != null) {
@@ -490,6 +503,20 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ private boolean hasMediaControlPermission(int pid, int uid) {
+ // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+ // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+ // check here.
+ if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else if (DEBUG) {
+ Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+ }
+ return false;
+ }
+
/**
* This checks if the component is an enabled notification listener for the
* specified user. Enabled components may only operate on behalf of the user
@@ -544,6 +571,14 @@ public class MediaSessionService extends SystemService implements Monitor {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
+ final int sessionCount = user.mUidToSessionCount.get(callerUid, 0);
+ if (sessionCount >= SESSION_CREATION_LIMIT_PER_UID
+ && !hasMediaControlPermission(callerPid, callerUid)) {
+ throw new RuntimeException("Created too many sessions. count="
+ + sessionCount + ")");
+ }
+ user.mUidToSessionCount.put(callerUid, sessionCount + 1);
+
user.mPriorityStack.addSession(session);
mHandler.postSessionsChanged(session);
@@ -723,6 +758,7 @@ public class MediaSessionService extends SystemService implements Monitor {
mOnMediaKeyEventDispatchedListeners = new HashMap<>();
private final HashMap<IBinder, OnMediaKeyEventSessionChangedListenerRecord>
mOnMediaKeyEventSessionChangedListeners = new HashMap<>();
+ private final SparseIntArray mUidToSessionCount = new SparseIntArray();
private PendingIntent mLastMediaButtonReceiver;
private ComponentName mRestoredMediaButtonReceiver;
@@ -1954,20 +1990,6 @@ public class MediaSessionService extends SystemService implements Monitor {
return resolvedUserId;
}
- private boolean hasMediaControlPermission(int pid, int uid) {
- // Check if it's system server or has MEDIA_CONTENT_CONTROL.
- // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
- // check here.
- if (uid == Process.SYSTEM_UID || mContext.checkPermission(
- android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- } else if (DEBUG) {
- Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
- }
- return false;
- }
-
private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName)
throws RemoteException {
// You may not access another user's content as an enabled listener.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6f43952a3f58..7cc67324032a 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -251,8 +251,8 @@ import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
-import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.pm.PackageManagerService;
@@ -413,8 +413,8 @@ public class NotificationManagerService extends SystemService {
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
- private Light mNotificationLight;
- Light mAttentionLight;
+ private LogicalLight mNotificationLight;
+ LogicalLight mAttentionLight;
private long[] mFallbackVibrationPattern;
private boolean mUseAttentionLight;
@@ -1753,7 +1753,7 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
- void setLights(Light light) {
+ void setLights(LogicalLight light) {
mNotificationLight = light;
mAttentionLight = light;
mNotificationPulseEnabled = true;
@@ -7875,7 +7875,7 @@ public class NotificationManagerService extends SystemService {
NotificationRecord.Light light = ledNotification.getLight();
if (light != null && mNotificationPulseEnabled) {
// pulse repeatedly
- mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
+ mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
light.onMs, light.offMs);
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 78e17192ed58..9dff7754c4f3 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -302,8 +302,9 @@ public class AppsFilter {
* initiating uid.
*/
public void grantImplicitAccess(int callingUid, int targetUid) {
- if (mImplicitlyQueryable.add(targetUid, callingUid) && DEBUG_LOGGING) {
- Slog.wtf(TAG, "implicit access granted: " + callingUid + " -> " + targetUid);
+ if (targetUid != callingUid
+ && mImplicitlyQueryable.add(targetUid, callingUid) && DEBUG_LOGGING) {
+ Slog.wtf(TAG, "implicit access granted: " + targetUid + " -> " + callingUid);
}
}
@@ -511,6 +512,10 @@ public class AppsFilter {
}
return true;
}
+ if (targetPkg.isStaticSharedLibrary()) {
+ // not an app, this filtering takes place at a higher level
+ return false;
+ }
final String targetName = targetPkg.getPackageName();
Trace.beginSection("getAppId");
final int callingAppId;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ed955a260a52..ef2873358cd4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static android.content.pm.DataLoaderType.INCREMENTAL;
import static android.content.pm.DataLoaderType.STREAMING;
+import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -60,6 +61,7 @@ import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderManager;
import android.content.pm.DataLoaderParams;
+import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.FileSystemControlParcel;
import android.content.pm.IDataLoader;
import android.content.pm.IDataLoaderStatusListener;
@@ -203,8 +205,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
+ private static final String ATTR_LOCATION = "location";
private static final String ATTR_LENGTH_BYTES = "lengthBytes";
private static final String ATTR_METADATA = "metadata";
+ private static final String ATTR_SIGNATURE = "signature";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
@@ -303,22 +307,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private int mParentSessionId;
static class FileInfo {
+ public final int location;
public final String name;
public final Long lengthBytes;
public final byte[] metadata;
+ public final byte[] signature;
- public static FileInfo added(String name, Long lengthBytes, byte[] metadata) {
- return new FileInfo(name, lengthBytes, metadata);
+ public static FileInfo added(int location, String name, Long lengthBytes, byte[] metadata,
+ byte[] signature) {
+ return new FileInfo(location, name, lengthBytes, metadata, signature);
}
- public static FileInfo removed(String name) {
- return new FileInfo(name, -1L, null);
+ public static FileInfo removed(int location, String name) {
+ return new FileInfo(location, name, -1L, null, null);
}
- FileInfo(String name, Long lengthBytes, byte[] metadata) {
+ FileInfo(int location, String name, Long lengthBytes, byte[] metadata, byte[] signature) {
+ this.location = location;
this.name = name;
this.lengthBytes = lengthBytes;
this.metadata = metadata;
+ this.signature = signature;
}
}
@@ -597,6 +606,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
info.isStagedSessionReady = mStagedSessionReady;
info.isStagedSessionFailed = mStagedSessionFailed;
info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
+ info.createdMillis = createdMillis;
info.updatedMillis = updatedMillis;
}
return info;
@@ -2325,11 +2335,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
- public void addFile(String name, long lengthBytes, byte[] metadata) {
+ public DataLoaderParamsParcel getDataLoaderParams() {
+ return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
+ }
+
+ @Override
+ public void addFile(int location, String name, long lengthBytes, byte[] metadata,
+ byte[] signature) {
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
}
+ if (!isIncrementalInstallation()) {
+ if (location != LOCATION_DATA_APP) {
+ throw new IllegalArgumentException(
+ "Non-incremental installation only supports /data/app placement: " + name);
+ }
+ }
// Use installer provided name for now; we always rename later
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid name: " + name);
@@ -2338,12 +2360,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("addFile");
- mFiles.add(FileInfo.added(name, lengthBytes, metadata));
+ mFiles.add(FileInfo.added(location, name, lengthBytes, metadata, signature));
}
}
@Override
- public void removeFile(String name) {
+ public void removeFile(int location, String name) {
if (!isDataLoaderInstallation()) {
throw new IllegalStateException(
"Cannot add files to non-data loader installation session.");
@@ -2356,7 +2378,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("removeFile");
- mFiles.add(FileInfo.removed(getRemoveMarkerName(name)));
+ mFiles.add(FileInfo.removed(location, getRemoveMarkerName(name)));
}
}
@@ -2891,9 +2913,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
for (FileInfo fileInfo : mFiles) {
out.startTag(null, TAG_SESSION_FILE);
+ writeIntAttribute(out, ATTR_LOCATION, fileInfo.location);
writeStringAttribute(out, ATTR_NAME, fileInfo.name);
writeLongAttribute(out, ATTR_LENGTH_BYTES, fileInfo.lengthBytes);
writeByteArrayAttribute(out, ATTR_METADATA, fileInfo.metadata);
+ writeByteArrayAttribute(out, ATTR_SIGNATURE, fileInfo.signature);
out.endTag(null, TAG_SESSION_FILE);
}
}
@@ -3024,9 +3048,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
}
if (TAG_SESSION_FILE.equals(in.getName())) {
- files.add(new FileInfo(readStringAttribute(in, ATTR_NAME),
+ files.add(new FileInfo(
+ readIntAttribute(in, ATTR_LOCATION, 0),
+ readStringAttribute(in, ATTR_NAME),
readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
- readByteArrayAttribute(in, ATTR_METADATA)));
+ readByteArrayAttribute(in, ATTR_METADATA),
+ readByteArrayAttribute(in, ATTR_SIGNATURE)));
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3a333136abe6..ca4ae0277aaf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -185,6 +185,7 @@ import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
@@ -3158,6 +3159,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
// SELinux domain.
setting.fixSeInfoLocked();
+ setting.updateProcesses();
}
// Now that we know all the packages we are keeping,
@@ -17697,7 +17699,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
/*
- * This method deletes the package from internal data structures. If the DONT_DELETE_DATA
+ * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
* flag is not set, the data directory is removed as well.
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
@@ -23487,6 +23489,20 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+ synchronized (mLock) {
+ return getProcessesForUidLocked(uid);
+ }
+ }
+
+ @Override
+ public int[] getPermissionGids(String permissionName, int userId) {
+ synchronized (mLock) {
+ return getPermissionGidsLocked(permissionName, userId);
+ }
+ }
+
+ @Override
public boolean isOnlyCoreApps() {
return PackageManagerService.this.isOnlyCoreApps();
}
@@ -23741,6 +23757,30 @@ public class PackageManagerService extends IPackageManager.Stub
return res != null ? res : EmptyArray.STRING;
}
+ @GuardedBy("mLock")
+ public ArrayMap<String, ProcessInfo> getProcessesForUidLocked(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final SettingBase obj = mSettings.getSettingLPr(appId);
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ return PackageInfoUtils.generateProcessInfo(sus.processes, 0);
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return PackageInfoUtils.generateProcessInfo(ps.pkg.getProcesses(), 0);
+ }
+ return null;
+ }
+
+ @GuardedBy("mLock")
+ public int[] getPermissionGidsLocked(String permissionName, int userId) {
+ BasePermission perm
+ = mPermissionManager.getPermissionSettings().getPermission(permissionName);
+ if (perm != null) {
+ return perm.computeGids(userId);
+ }
+ return null;
+ }
+
@Override
public int getRuntimePermissionsVersion(@UserIdInt int userId) {
Preconditions.checkArgumentNonnegative(userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 83840067ecc2..e7f6b8982b04 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -2970,7 +2971,7 @@ class PackageManagerShellCommand extends ShellCommand {
// 1. Single file from stdin.
if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
String name = "base." + (isApex ? "apex" : "apk");
- session.addFile(name, sessionSizeBytes, STDIN_PATH_BYTES);
+ session.addFile(LOCATION_DATA_APP, name, sessionSizeBytes, STDIN_PATH_BYTES, null);
return 0;
}
@@ -2994,7 +2995,7 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- session.addFile(name, sizeBytes, STDIN_PATH_BYTES);
+ session.addFile(LOCATION_DATA_APP, name, sizeBytes, STDIN_PATH_BYTES, null);
continue;
}
@@ -3004,7 +3005,7 @@ class PackageManagerShellCommand extends ShellCommand {
String name = new File(inPath).getName();
byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
- session.addFile(name, -1, metadata);
+ session.addFile(LOCATION_DATA_APP, name, -1, metadata, null);
}
return 0;
} finally {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index a814cb8942e2..281c44a61153 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -115,8 +115,8 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
}
@Override
- public boolean onPrepareImage(Collection<InstallationFile> addedFiles,
- Collection<String> removedFiles) {
+ public boolean onPrepareImage(@NonNull Collection<InstallationFile> addedFiles,
+ @NonNull Collection<String> removedFiles) {
final int commandId = extractShellCommandId(mParams.getArguments());
if (commandId == INVALID_SHELL_COMMAND_ID) {
return false;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 0a42ccf1c5ba..b9bb9e0ad0d8 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -19,7 +19,9 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
import android.service.pm.PackageServiceDumpProto;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
@@ -51,6 +53,8 @@ public final class SharedUserSetting extends SettingBase {
final PackageSignatures signatures = new PackageSignatures();
Boolean signaturesChanged;
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
+
SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
super(_pkgFlags, _pkgPrivateFlags);
uidFlags = _pkgFlags;
@@ -72,6 +76,25 @@ public final class SharedUserSetting extends SettingBase {
proto.end(token);
}
+ void addProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> newProcs) {
+ if (newProcs != null) {
+ final int numProcs = newProcs.size();
+ if (processes == null) {
+ processes = new ArrayMap<>(numProcs);
+ }
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess newProc = newProcs.valueAt(i);
+ ComponentParseUtils.ParsedProcess proc = processes.get(newProc.name);
+ if (proc == null) {
+ proc = new ComponentParseUtils.ParsedProcess(newProc);
+ processes.put(newProc.name, proc);
+ } else {
+ proc.addStateFrom(newProc);
+ }
+ }
+ }
+ }
+
boolean removePackage(PackageSetting packageSetting) {
if (!packages.remove(packageSetting)) {
return false;
@@ -91,6 +114,8 @@ public final class SharedUserSetting extends SettingBase {
}
setPrivateFlags(aggregatedPrivateFlags);
}
+ // recalculate processes.
+ updateProcesses();
return true;
}
@@ -104,6 +129,9 @@ public final class SharedUserSetting extends SettingBase {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
}
+ if (packageSetting.pkg != null) {
+ addProcesses(packageSetting.pkg.getProcesses());
+ }
}
public @Nullable List<AndroidPackage> getPackages() {
@@ -148,6 +176,16 @@ public final class SharedUserSetting extends SettingBase {
}
}
+ /**
+ * Update tracked data about processes based on all known packages in the shared user ID.
+ */
+ public void updateProcesses() {
+ processes = null;
+ for (int i = packages.size() - 1; i >= 0; i--) {
+ addProcesses(packages.valueAt(i).pkg.getProcesses());
+ }
+ }
+
/** Returns userIds which doesn't have any packages with this sharedUserId */
public int[] getNotInstalledUserIds() {
int[] excludedUserIds = null;
@@ -176,6 +214,17 @@ public final class SharedUserSetting extends SettingBase {
this.packages.clear();
this.packages.addAll(sharedUser.packages);
this.signaturesChanged = sharedUser.signaturesChanged;
+ if (sharedUser.processes != null) {
+ final int numProcs = sharedUser.processes.size();
+ this.processes = new ArrayMap<>(numProcs);
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess proc =
+ new ComponentParseUtils.ParsedProcess(sharedUser.processes.valueAt(i));
+ this.processes.put(proc.name, proc);
+ }
+ } else {
+ this.processes = null;
+ }
return this;
}
}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index e08c004866ea..157f8256ce50 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -74,7 +74,7 @@ final class GlobalKeyManager {
Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
.setComponent(component)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .putExtra(Intent.EXTRA_KEY_EVENT, event);
+ .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event));
context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
return true;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ec9049ee05ee..c3e7f62e4f31 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4876,7 +4876,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBootMsgDialog.getWindow().setDimAmount(1);
WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
- lp.setFitWindowInsetsTypes(0 /* types */);
+ lp.setFitInsetsTypes(0 /* types */);
mBootMsgDialog.getWindow().setAttributes(lp);
mBootMsgDialog.setCancelable(false);
mBootMsgDialog.show();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index ca368694ca92..3f3a13368ffc 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -16,8 +16,8 @@
package com.android.server.power;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -96,8 +96,8 @@ import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
@@ -257,7 +257,7 @@ public final class PowerManagerService extends SystemService
private WirelessChargerDetector mWirelessChargerDetector;
private SettingsObserver mSettingsObserver;
private DreamManagerInternal mDreamManager;
- private Light mAttentionLight;
+ private LogicalLight mAttentionLight;
private InattentiveSleepWarningController mInattentiveSleepWarningOverlayController;
@@ -3347,7 +3347,7 @@ public final class PowerManagerService extends SystemService
}
private void setAttentionLightInternal(boolean on, int color) {
- Light light;
+ LogicalLight light;
synchronized (mLock) {
if (!mSystemReady) {
return;
@@ -3356,7 +3356,7 @@ public final class PowerManagerService extends SystemService
}
// Control light outside of lock.
- light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
}
private void setDozeAfterScreenOffInternal(boolean on) {
diff --git a/services/core/java/com/android/server/utils/FlagNamespaceUtils.java b/services/core/java/com/android/server/utils/FlagNamespaceUtils.java
deleted file mode 100644
index f8c7447fc55d..000000000000
--- a/services/core/java/com/android/server/utils/FlagNamespaceUtils.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.utils;
-
-import android.annotation.Nullable;
-import android.provider.DeviceConfig;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.RescueParty;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Utilities for interacting with the {@link android.provider.DeviceConfig}.
- *
- * @hide
- */
-public final class FlagNamespaceUtils {
- /**
- * Special String used for communicating through {@link #RESET_PLATFORM_PACKAGE_FLAG} that
- * Settings were reset by the RescueParty, no actual namespace with this name exists in
- * {@link DeviceConfig}.
- */
- public static final String NAMESPACE_NO_PACKAGE = "no_package";
-
- /**
- * Name of the special namespace in DeviceConfig table used for communicating resets.
- */
- @VisibleForTesting
- public static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace";
- /**
- * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link
- * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the
- * first time flags are written to the new namespace in the {@link DeviceConfig}.
- */
- @VisibleForTesting
- public static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces";
- /**
- * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter
- * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently
- * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given
- * namespace flags are reset.
- */
- @VisibleForTesting
- public static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package";
- private static final String DELIMITER = ":";
- /**
- * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG}
- * when communicating recently reset by the RescueParty namespace values.
- */
- private static final int MAX_COUNTER_VALUE = 50;
-
- private static int sKnownResetNamespacesFlagCounter = -1;
-
- /**
- * Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
- * {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for each namespace
- * in the consumed namespacesList. These flags are used for communicating the namespaces
- * (aka platform packages) whose flags in {@link DeviceConfig} were just reset
- * by the RescueParty.
- */
- public static void addToKnownResetNamespaces(@Nullable List<String> namespacesList) {
- if (namespacesList == null) {
- return;
- }
- for (String namespace : namespacesList) {
- addToKnownResetNamespaces(namespace);
- }
- }
-
- /**
- * Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
- * {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for the consumed namespace.
- * This flag is used for communicating the namespace (aka platform package) whose flags
- * in {@link DeviceConfig} were just reset by the RescueParty.
- */
- public static void addToKnownResetNamespaces(String namespace) {
- int nextFlagCounter = incrementAndRetrieveResetNamespacesFlagCounter();
- DeviceConfig.setProperty(NAMESPACE_RESCUE_PARTY,
- RESET_PLATFORM_PACKAGE_FLAG + nextFlagCounter,
- namespace, /*makeDefault=*/ true);
- }
-
- /**
- * Reset all namespaces in DeviceConfig with consumed resetMode.
- */
- public static void resetDeviceConfig(int resetMode) {
- resetDeviceConfig(resetMode, getAllKnownDeviceConfigNamespacesList());
- }
-
- /**
- * Reset all consumed namespaces in DeviceConfig with consumed resetMode.
- */
- public static void resetDeviceConfig(int resetMode, List<String> namespacesList) {
- for (String namespace : namespacesList) {
- DeviceConfig.resetToDefaults(resetMode, namespace);
- }
- addToKnownResetNamespaces(namespacesList);
- }
-
- /**
- * Resets known reset namespaces flag counter for tests only.
- */
- @VisibleForTesting
- public static void resetKnownResetNamespacesFlagCounterForTest() {
- sKnownResetNamespacesFlagCounter = -1;
- }
-
- /**
- * Returns a list of all known DeviceConfig namespaces, except for the special {@link
- * #NAMESPACE_RESCUE_PARTY}
- */
- private static List<String> getAllKnownDeviceConfigNamespacesList() {
- String namespacesStr = DeviceConfig.getProperty(NAMESPACE_RESCUE_PARTY,
- ALL_KNOWN_NAMESPACES_FLAG);
- List<String> namespacesList = toStringList(namespacesStr);
- namespacesList.remove(NAMESPACE_RESCUE_PARTY);
- return namespacesList;
- }
-
- private static List<String> toStringList(String serialized) {
- if (serialized == null || serialized.length() == 0) {
- return new ArrayList<>();
- }
- return Arrays.asList(serialized.split(DELIMITER));
- }
-
- private static int incrementAndRetrieveResetNamespacesFlagCounter() {
- sKnownResetNamespacesFlagCounter++;
- if (sKnownResetNamespacesFlagCounter == MAX_COUNTER_VALUE) {
- sKnownResetNamespacesFlagCounter = 0;
- }
- return sKnownResetNamespacesFlagCounter;
- }
-}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 36e97755ab8a..2115f7ccfe98 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3433,6 +3433,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.print("mDefaultWallpaperComponent="); pw.println(mDefaultWallpaperComponent);
+ pw.print("mImageWallpaper="); pw.println(mImageWallpaper);
+
synchronized (mLock) {
pw.println("System wallpaper state:");
for (int i = 0; i < mWallpaperMap.size(); i++) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4f1d40e39314..f8df883a3e1c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -63,7 +63,6 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -362,7 +361,6 @@ public class DisplayPolicy {
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpNavFrame = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
- private static final int[] sTmpTypesAndSides = new int[2];
private WindowState mTopFullscreenOpaqueWindowState;
private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -888,6 +886,21 @@ public class DisplayPolicy {
// Toasts can't be clickable
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
break;
+
+ case TYPE_BASE_APPLICATION:
+
+ // A non-translucent main app window isn't allowed to fit insets, as it would create
+ // a hole on the display!
+ if (attrs.isFullscreen() && win.mActivityRecord != null
+ && win.mActivityRecord.fillsParent()
+ && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
+ && attrs.getFitInsetsTypes() != 0) {
+ throw new RuntimeException("Illegal attributes: Main activity window that isn't"
+ + " translucent trying to fit insets: "
+ + attrs.getFitInsetsTypes()
+ + " attrs=" + attrs);
+ }
+ break;
}
}
@@ -1247,7 +1260,7 @@ public class DisplayPolicy {
if (layoutInScreenAndInsetDecor && !screenDecor) {
if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- || (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) == 0) {
+ || (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
outFrame.set(displayFrames.mUnrestricted);
} else {
outFrame.set(displayFrames.mRestricted);
@@ -1300,21 +1313,6 @@ public class DisplayPolicy {
}
}
- private static void getImpliedTypesAndSidesToFit(LayoutParams attrs, int[] typesAndSides) {
- typesAndSides[0] = attrs.getFitWindowInsetsTypes();
- typesAndSides[1] = attrs.getFitWindowInsetsSides();
- final boolean forceDrawsBarBackgrounds =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || forceDrawsBarBackgrounds) {
- if ((attrs.privateFlags & PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND) != 0) {
- typesAndSides[1] &= ~Side.BOTTOM;
- } else {
- typesAndSides[0] &= ~Type.systemBars();
- }
- }
- }
-
// TODO(b/118118435): remove after migration
private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
int impliedFlags = 0;
@@ -1878,16 +1876,15 @@ public class DisplayPolicy {
sf.set(displayFrames.mStable);
if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- getImpliedTypesAndSidesToFit(attrs, sTmpTypesAndSides);
- final @InsetsType int typesToFit = sTmpTypesAndSides[0];
- final @InsetsSide int sidesToFit = sTmpTypesAndSides[1];
+ final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
+ final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
final Rect dfu = displayFrames.mUnrestricted;
Insets insets = Insets.of(0, 0, 0, 0);
for (int i = types.size() - 1; i >= 0; i--) {
insets = Insets.max(insets, mDisplayContent.getInsetsPolicy()
.getInsetsForDispatch(win).getSource(types.valueAt(i))
- .calculateInsets(dfu, attrs.getFitIgnoreVisibility()));
+ .calculateInsets(dfu, attrs.isFitInsetsIgnoringVisibility()));
}
final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index bef1442c73c5..ef6f84703723 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -190,7 +190,7 @@ public class ImmersiveModeConfirmation {
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
- lp.setFitWindowInsetsTypes(lp.getFitWindowInsetsTypes() & ~Type.statusBars());
+ lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~Type.statusBars());
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("ImmersiveModeConfirmation");
lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 38a7000803bd..828775a4b934 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -52,7 +52,6 @@ class TaskSnapshotPersister {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
private static final String SNAPSHOTS_DIRNAME = "snapshots";
private static final String REDUCED_POSTFIX = "_reduced";
- private static final float REDUCED_SCALE = .5f;
private static final float LOW_RAM_REDUCED_SCALE = .8f;
static final boolean DISABLE_FULL_SIZED_BITMAPS = ActivityManager.isLowRamDeviceStatic();
private static final long DELAY_MS = 100;
@@ -84,8 +83,13 @@ class TaskSnapshotPersister {
TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
mDirectoryResolver = resolver;
- mReducedScale = ActivityManager.isLowRamDeviceStatic()
- ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
+
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ mReducedScale = LOW_RAM_REDUCED_SCALE;
+ } else {
+ mReducedScale = service.mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_reducedTaskSnapshotScale);
+ }
mUse16BitFormat = service.mContext.getResources().getBoolean(
com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 81a4c682e809..8d4ad28972e9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -71,6 +71,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
@@ -1367,52 +1368,10 @@ public class WindowManagerService extends IWindowManager.Stub
boolean addToastWindowRequiresToken = false;
if (token == null) {
- if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
- ProtoLog.w(WM_ERROR, "Attempted to add application window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (rootType == TYPE_INPUT_METHOD) {
- ProtoLog.w(WM_ERROR, "Attempted to add input method window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (rootType == TYPE_VOICE_INTERACTION) {
- ProtoLog.w(WM_ERROR,
- "Attempted to add voice interaction window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (rootType == TYPE_WALLPAPER) {
- ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (rootType == TYPE_DREAM) {
- ProtoLog.w(WM_ERROR, "Attempted to add Dream window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (rootType == TYPE_QS_DIALOG) {
- ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with unknown token "
- + "%s. Aborting.", attrs.token);
+ if (!unprivilegedAppCanCreateTokenWith(parentWindow, callingUid, type,
+ rootType, attrs.token, attrs.packageName)) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
- ProtoLog.w(WM_ERROR,
- "Attempted to add Accessibility overlay window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_TOAST) {
- // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
- if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
- parentWindow)) {
- ProtoLog.w(WM_ERROR, "Attempted to add a toast window with unknown token "
- + "%s. Aborting.", attrs.token);
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- }
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
final boolean isRoundedCornerOverlay =
(attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
@@ -1697,6 +1656,56 @@ public class WindowManagerService extends IWindowManager.Stub
return res;
}
+ private boolean unprivilegedAppCanCreateTokenWith(WindowState parentWindow,
+ int callingUid, int type, int rootType, IBinder tokenForLog, String packageName) {
+ if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
+ ProtoLog.w(WM_ERROR, "Attempted to add application window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_INPUT_METHOD) {
+ ProtoLog.w(WM_ERROR, "Attempted to add input method window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_VOICE_INTERACTION) {
+ ProtoLog.w(WM_ERROR,
+ "Attempted to add voice interaction window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_WALLPAPER) {
+ ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_DREAM) {
+ ProtoLog.w(WM_ERROR, "Attempted to add Dream window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_QS_DIALOG) {
+ ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
+ ProtoLog.w(WM_ERROR,
+ "Attempted to add Accessibility overlay window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ if (type == TYPE_TOAST) {
+ // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+ if (doesAddToastWindowRequireToken(packageName, callingUid, parentWindow)) {
+ ProtoLog.w(WM_ERROR, "Attempted to add a toast window with unknown token "
+ + "%s. Aborting.", tokenForLog);
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Get existing {@link DisplayContent} or create a new one if the display is registered in
* DisplayManager.
@@ -2501,16 +2510,36 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void addWindowToken(IBinder binder, int type, int displayId) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+ addWindowContextToken(binder, type, displayId, null);
+ }
+
+ @Override
+ public int addWindowContextToken(IBinder binder, int type, int displayId, String packageName) {
+ final boolean callerCanManageAppTokens =
+ checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()");
+ if (!callerCanManageAppTokens) {
+ // TODO(window-context): refactor checkAddPermission to not take attrs.
+ LayoutParams attrs = new LayoutParams(type);
+ attrs.packageName = packageName;
+ final int res = mPolicy.checkAddPermission(attrs, new int[1]);
+ if (res != ADD_OKAY) {
+ return res;
+ }
}
synchronized (mGlobalLock) {
+ if (!callerCanManageAppTokens) {
+ if (!unprivilegedAppCanCreateTokenWith(null, Binder.getCallingUid(), type, type,
+ null, packageName) || packageName == null) {
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+ }
+ }
+
final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
if (dc == null) {
ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s"
+ " for non-exiting displayId=%d", binder, displayId);
- return;
+ return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
WindowToken token = dc.getWindowToken(binder);
@@ -2518,15 +2547,28 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s"
+ " for already created window token: %s"
+ " displayId=%d", binder, token, displayId);
- return;
+ return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
+ // TODO(window-container): Clean up dead tokens
if (type == TYPE_WALLPAPER) {
- new WallpaperWindowToken(this, binder, true, dc,
- true /* ownerCanManageAppTokens */);
+ new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens);
} else {
- new WindowToken(this, binder, type, true, dc, true /* ownerCanManageAppTokens */);
+ new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens);
}
}
+ return WindowManagerGlobal.ADD_OKAY;
+ }
+
+ @Override
+ public boolean isWindowToken(IBinder binder) {
+ synchronized (mGlobalLock) {
+ final WindowToken windowToken = mRoot.getWindowToken(binder);
+ if (windowToken == null) {
+ return false;
+ }
+ // We don't allow activity tokens in WindowContext. TODO(window-context): rename method
+ return windowToken.asActivityRecord() == null;
+ }
}
@Override
@@ -7885,4 +7927,33 @@ public class WindowManagerService extends IWindowManager.Stub
return mDisplayWindowSettings.shouldShowImeLocked(displayContent)
|| mForceDesktopModeOnExternalDisplays;
}
+
+ @Override
+ public void getWindowInsets(WindowManager.LayoutParams attrs,
+ int displayId, Rect outContentInsets, Rect outStableInsets,
+ DisplayCutout.ParcelableWrapper displayCutout) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ final WindowToken windowToken = dc.getWindowToken(attrs.token);
+ final ActivityRecord activity;
+ if (windowToken != null && windowToken.asActivityRecord() != null) {
+ activity = windowToken.asActivityRecord();
+ } else {
+ activity = null;
+ }
+ final Rect taskBounds = new Rect();
+ final boolean floatingStack;
+ if (activity != null && activity.getTask() != null) {
+ final Task task = activity.getTask();
+ task.getBounds(taskBounds);
+ floatingStack = task.isFloating();
+ } else {
+ floatingStack = false;
+ }
+ final DisplayFrames displayFrames = dc.mDisplayFrames;
+ final DisplayPolicy policy = dc.getDisplayPolicy();
+ policy.getLayoutHintLw(attrs, taskBounds, displayFrames, floatingStack,
+ new Rect(), outContentInsets, outStableInsets, displayCutout);
+ }
+ }
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c0891d739788..212a3a638634 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -312,7 +312,6 @@ private:
void updateInactivityTimeoutLocked();
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
void ensureSpriteControllerLocked();
- const DisplayViewport* findDisplayViewportLocked(int32_t displayId);
int32_t getPointerDisplayId();
void updatePointerDisplayLocked();
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
@@ -390,16 +389,6 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c
return false;
}
-const DisplayViewport* NativeInputManager::findDisplayViewportLocked(int32_t displayId)
- REQUIRES(mLock) {
- for (const DisplayViewport& v : mLocked.viewports) {
- if (v.displayId == displayId) {
- return &v;
- }
- }
- return nullptr;
-}
-
void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray) {
std::vector<DisplayViewport> viewports;
@@ -547,6 +536,8 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
outConfig->setDisplayViewports(mLocked.viewports);
+ outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId;
+
outConfig->disabledDevices = mLocked.disabledInputDevices;
} // release lock
}
@@ -564,8 +555,6 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
updateInactivityTimeoutLocked();
}
- updatePointerDisplayLocked();
-
return controller;
}
@@ -580,23 +569,6 @@ int32_t NativeInputManager::getPointerDisplayId() {
return pointerDisplayId;
}
-void NativeInputManager::updatePointerDisplayLocked() REQUIRES(mLock) {
- ATRACE_CALL();
-
- sp<PointerController> controller = mLocked.pointerController.promote();
- if (controller != nullptr) {
- const DisplayViewport* viewport = findDisplayViewportLocked(mLocked.pointerDisplayId);
- if (viewport == nullptr) {
- ALOGW("Can't find pointer display viewport, fallback to default display.");
- viewport = findDisplayViewportLocked(ADISPLAY_ID_DEFAULT);
- }
-
- if (viewport != nullptr) {
- controller->setDisplayViewport(*viewport);
- }
- }
-}
-
void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) {
if (mLocked.spriteController == nullptr) {
JNIEnv* env = jniEnv();
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 00436bb8ca70..08a759227526 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1208,6 +1208,22 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement
translateSingleGnssMeasurement(&(measurement_V2_1->v2_0), object);
SET(BasebandCn0DbHz, measurement_V2_1->basebandCN0DbHz);
+
+ if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) {
+ SET(ReceiverInterSignalBiasNs, measurement_V2_1->receiverInterSignalBiasNs);
+ }
+
+ if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) {
+ SET(ReceiverInterSignalBiasUncertaintyNs, measurement_V2_1->receiverInterSignalBiasUncertaintyNs);
+ }
+
+ if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) {
+ SET(SatelliteInterSignalBiasNs, measurement_V2_1->satelliteInterSignalBiasNs);
+ }
+
+ if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) {
+ SET(SatelliteInterSignalBiasUncertaintyNs, measurement_V2_1->satelliteInterSignalBiasUncertaintyNs);
+ }
}
template<class T>
@@ -1253,6 +1269,19 @@ void GnssMeasurementCallback::translateGnssClock(
template<>
void GnssMeasurementCallback::translateGnssClock(
+ JavaObject& object, const IGnssMeasurementCallback_V2_1::GnssClock& clock) {
+ JNIEnv* env = getJniEnv();
+ SET(ReferenceConstellationTypeForIsb,
+ static_cast<int32_t>(clock.referenceSignalTypeForIsb.constellation));
+ SET(ReferenceCarrierFrequencyHzForIsb, clock.referenceSignalTypeForIsb.carrierFrequencyHz);
+ SET(ReferenceCodeTypeForIsb,
+ env->NewStringUTF(clock.referenceSignalTypeForIsb.codeType.c_str()));
+
+ translateGnssClock(object, clock.v1_0);
+}
+
+template<>
+void GnssMeasurementCallback::translateGnssClock(
JavaObject& object, const IGnssMeasurementCallback_V2_0::GnssData& data) {
auto elapsedRealtime = data.elapsedRealtime;
uint16_t flags = static_cast<uint16_t>(elapsedRealtime.flags);
@@ -1265,6 +1294,20 @@ void GnssMeasurementCallback::translateGnssClock(
translateGnssClock(object, data.clock);
}
+template<>
+void GnssMeasurementCallback::translateGnssClock(
+ JavaObject& object, const IGnssMeasurementCallback_V2_1::GnssData& data) {
+ auto elapsedRealtime = data.elapsedRealtime;
+ uint16_t flags = static_cast<uint16_t>(elapsedRealtime.flags);
+ if (flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) {
+ SET(ElapsedRealtimeNanos, static_cast<uint64_t>(elapsedRealtime.timestampNs));
+ }
+ if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
+ SET(ElapsedRealtimeUncertaintyNanos, static_cast<double>(elapsedRealtime.timeUncertaintyNs));
+ }
+ translateGnssClock(object, data.clock);
+}
+
template<class T>
jobjectArray GnssMeasurementCallback::translateAllGnssMeasurements(JNIEnv* env,
const T* measurements,
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index c26629d28476..5c7f30576741 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -35,6 +35,7 @@
<xs:complexType name="nitsMap">
<xs:sequence>
<xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2"/>
+ <xs:element name="highBrightnessStart" minOccurs="0" type="nonNegativeDecimal"/>
</xs:sequence>
</xs:complexType>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e2b1b9bf1e2c..5a9c9457b423 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -9,7 +9,9 @@ package com.android.server.display.config {
public class NitsMap {
ctor public NitsMap();
+ method public java.math.BigDecimal getHighBrightnessStart();
method public java.util.List<com.android.server.display.config.Point> getPoint();
+ method public void setHighBrightnessStart(java.math.BigDecimal);
}
public class Point {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 8641059aebd5..43ee97dfa17b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -68,4 +68,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
return false;
}
+
+ public int getPersonalAppsSuspendedReasons(ComponentName admin) {
+ return 0;
+ }
+
+ public void setPersonalAppsSuspended(ComponentName admin, boolean suspended) {
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7830c60806ae..b6953f6e3e36 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -126,6 +127,7 @@ import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
+import android.app.admin.DevicePolicyManager.PersonalAppSuspensionReason;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
@@ -254,6 +256,7 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.SmsApplication;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
@@ -375,6 +378,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen";
+ private static final String TAG_PERSONAL_APPS_SUSPENDED = "personal-apps-suspended";
+
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -445,6 +450,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// A collection of user restrictions that are deprecated and should simply be ignored.
private static final Set<String> DEPRECATED_USER_RESTRICTIONS;
private static final String AB_DEVICE_KEY = "ro.build.ab_update";
+ // Permissions related to location which must not be granted automatically
+ private static final Set<String> LOCATION_PERMISSIONS;
static {
SECURE_SETTINGS_WHITELIST = new ArraySet<>();
@@ -489,6 +496,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DEPRECATED_USER_RESTRICTIONS = Sets.newHashSet(
UserManager.DISALLOW_ADD_MANAGED_PROFILE,
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
+
+ LOCATION_PERMISSIONS = Sets.newHashSet(
+ permission.ACCESS_FINE_LOCATION,
+ permission.ACCESS_BACKGROUND_LOCATION,
+ permission.ACCESS_COARSE_LOCATION);
}
/**
@@ -787,6 +799,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
long mPasswordTokenHandle = 0;
+ // Flag reflecting the current state of the personal apps suspension. This flag should
+ // only be written AFTER all the needed apps were suspended or unsuspended.
+ boolean mPersonalAppsSuspended = false;
+
public DevicePolicyData(int userHandle) {
mUserHandle = userHandle;
}
@@ -1016,6 +1032,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages";
private static final String TAG_FACTORY_RESET_PROTECTION_POLICY =
"factory_reset_protection_policy";
+ private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps";
DeviceAdminInfo info;
@@ -1138,6 +1155,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// represented as an empty list.
List<String> mCrossProfilePackages = Collections.emptyList();
+ // Whether the admin explicitly requires personal apps to be suspended
+ boolean mSuspendPersonalApps = false;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -1347,8 +1367,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName);
}
if (isLogoutEnabled) {
- writeAttributeValueToXml(
- out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled);
+ writeAttributeValueToXml(out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled);
}
if (startUserSessionMessage != null) {
writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage);
@@ -1369,6 +1388,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mFactoryResetProtectionPolicy.writeToXml(out);
out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY);
}
+ if (mSuspendPersonalApps) {
+ writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps);
+ }
}
void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1605,6 +1627,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
} else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) {
mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml(
parser);
+ } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) {
+ mSuspendPersonalApps = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -3411,6 +3436,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
out.endTag(null, TAG_PROTECTED_PACKAGES);
}
+ if (policy.mPersonalAppsSuspended) {
+ out.startTag(null, TAG_PERSONAL_APPS_SUSPENDED);
+ out.attribute(null, ATTR_VALUE,
+ Boolean.toString(policy.mPersonalAppsSuspended));
+ out.endTag(null, TAG_PERSONAL_APPS_SUSPENDED);
+ }
+
out.endTag(null, "policies");
out.endDocument();
@@ -3627,6 +3659,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
} else if (TAG_PROTECTED_PACKAGES.equals(tag)) {
policy.mProtectedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+ } else if (TAG_PERSONAL_APPS_SUSPENDED.equals(tag)) {
+ policy.mPersonalAppsSuspended =
+ Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -3767,6 +3802,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
maybeMigrateToProfileOnOrganizationOwnedDeviceLocked();
}
+ checkPackageSuspensionOnBoot();
break;
case SystemService.PHASE_BOOT_COMPLETED:
ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
@@ -3774,6 +3810,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void checkPackageSuspensionOnBoot() {
+ int profileUserId = UserHandle.USER_NULL;
+ final boolean shouldSuspend;
+ synchronized (getLockObject()) {
+ for (final int userId : mOwners.getProfileOwnerKeys()) {
+ if (mOwners.isProfileOwnerOfOrganizationOwnedDevice(userId)) {
+ profileUserId = userId;
+ break;
+ }
+ }
+
+ if (profileUserId == UserHandle.USER_NULL) {
+ shouldSuspend = false;
+ } else {
+ shouldSuspend = getProfileOwnerAdminLocked(profileUserId).mSuspendPersonalApps;
+ }
+ }
+
+ final boolean suspended = getUserData(UserHandle.USER_SYSTEM).mPersonalAppsSuspended;
+ if (suspended != shouldSuspend) {
+ suspendPersonalAppsInternal(shouldSuspend, UserHandle.USER_SYSTEM);
+ }
+
+ if (shouldSuspend) {
+ sendPersonalAppsSuspendedNotification(profileUserId);
+ }
+ }
+
private void onLockSettingsReady() {
getUserData(UserHandle.USER_SYSTEM);
loadOwners();
@@ -3886,11 +3950,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
+ maybeUpdatePersonalAppsSuspendedNotification(userId);
}
@Override
void handleStopUser(int userId) {
stopOwnerService(userId, "stop-user");
+ maybeUpdatePersonalAppsSuspendedNotification(userId);
}
private void startOwnerService(int userId, String actionForLog) {
@@ -9749,7 +9815,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
AccessibilityManager accessibilityManager = getAccessibilityManagerForUser(userId);
enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ FEEDBACK_ALL_MASK);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -10671,30 +10737,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
- boolean hidden) {
- int callingUserId = UserHandle.getCallingUserId();
- boolean result = false;
+ boolean hidden, boolean parent) {
+ final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
+ : UserHandle.getCallingUserId();
+ boolean result;
+
synchronized (getLockObject()) {
// Ensure the caller is a DO/PO or a package access delegate.
enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
DELEGATION_PACKAGE_ACCESS);
- long id = mInjector.binderClearCallingIdentity();
- try {
- result = mIPackageManager
- .setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId);
- } catch (RemoteException re) {
- // shouldn't happen
- Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ if (parent) {
+ getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
+ // Ensure the package provided is a system package, this is to ensure that this
+ // API cannot be used to leak if certain non-system package exists in the person
+ // profile.
+ mInjector.binderWithCleanCallingIdentity(() ->
+ enforcePackageIsSystemPackage(packageName, hidden, userId));
}
+
+ result = mInjector.binderWithCleanCallingIdentity(() -> mIPackageManager
+ .setApplicationHiddenSettingAsUser(packageName, hidden, userId));
}
final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_APPLICATION_HIDDEN)
.setAdmin(callerPackage)
.setBoolean(isDelegate)
+ .setBoolean(parent)
.setStrings(packageName, hidden ? "hidden" : "not_hidden")
.write();
return result;
@@ -10702,24 +10773,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean isApplicationHidden(ComponentName who, String callerPackage,
- String packageName) {
- int callingUserId = UserHandle.getCallingUserId();
+ String packageName, boolean parent) {
+ final int userId = parent ? getProfileParentId(UserHandle.getCallingUserId())
+ : UserHandle.getCallingUserId();
+
synchronized (getLockObject()) {
// Ensure the caller is a DO/PO or a package access delegate.
enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
DELEGATION_PACKAGE_ACCESS);
- long id = mInjector.binderClearCallingIdentity();
- try {
- return mIPackageManager.getApplicationHiddenSettingAsUser(
- packageName, callingUserId);
- } catch (RemoteException re) {
- // shouldn't happen
- Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ if (parent) {
+ getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent);
+ // Ensure the package provided is a system package.
+ mInjector.binderWithCleanCallingIdentity(() ->
+ enforcePackageIsSystemPackage(packageName, false, userId));
}
- return false;
+
+ return mInjector.binderWithCleanCallingIdentity(
+ () -> mIPackageManager.getApplicationHiddenSettingAsUser(packageName, userId));
+ }
+ }
+
+ private void enforcePackageIsSystemPackage(String packageName, boolean hidden, int userId)
+ throws RemoteException {
+ int flags = PackageManager.MATCH_SYSTEM_ONLY;
+ // If the package is currently hidden then it is considered uninstalled and
+ // the MATCH_UNINSTALLED_PACKAGES flag has to be added.
+ if (!hidden) {
+ flags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ }
+ PackageInfo packageInfo = mIPackageManager.getPackageInfo(packageName, flags, userId);
+ if (packageInfo == null || !packageInfo.applicationInfo.isSystemApp()) {
+ throw new IllegalArgumentException(
+ "The provided package is not a system package");
}
}
@@ -12124,7 +12211,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
LocalDate.now());
}
synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
if (policy == null) {
mOwners.clearSystemUpdatePolicy();
} else {
@@ -12133,9 +12221,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
mOwners.writeDeviceOwner();
}
- mContext.sendBroadcastAsUser(
+ mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(
new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED),
- UserHandle.SYSTEM);
+ UserHandle.SYSTEM));
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY)
.setAdmin(who)
@@ -12390,6 +12478,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
true);
}
+ // Prevent granting location-related permissions without user consent.
+ if (LOCATION_PERMISSIONS.contains(permission)
+ && grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
+ && !isUnattendedManagedKioskUnchecked()) {
+ callback.sendResult(null);
+ return;
+ }
+
if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
|| grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
|| grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
@@ -14789,7 +14885,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.setAdmin(admin)
.setBoolean(isDeviceAB())
.write();
- enforceDeviceOwner(admin);
+ enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
mInjector.binderWithCleanCallingIdentity(() -> {
UpdateInstaller updateInstaller;
if (isDeviceAB()) {
@@ -14981,23 +15077,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- @Override
- public boolean isUnattendedManagedKiosk() {
- if (!mHasFeature) {
- return false;
- }
- enforceManageUsers();
- long id = mInjector.binderClearCallingIdentity();
+ private boolean isUnattendedManagedKioskUnchecked() {
try {
return isManagedKioskInternal()
&& getPowerManagerInternal().wasDeviceIdleFor(UNATTENDED_MANAGED_KIOSK_MS);
} catch (RemoteException e) {
throw new IllegalStateException(e);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
}
}
+ @Override
+ public boolean isUnattendedManagedKiosk() {
+ if (!mHasFeature) {
+ return false;
+ }
+ enforceManageUsers();
+ return mInjector.binderWithCleanCallingIdentity(() -> isUnattendedManagedKioskUnchecked());
+ }
+
/**
* Returns whether the device is currently being used as a publicly-accessible dedicated device.
* Assumes that feature checks and permission checks have already been performed, and that the
@@ -15166,4 +15263,121 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
return mInjector.settingsGlobalGetInt(Settings.Global.COMMON_CRITERIA_MODE, 0) != 0;
}
+
+ @Override
+ public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) {
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
+ false /* parent */);
+ // DO shouldn't be able to use this method.
+ enforceProfileOwnerOfOrganizationOwnedDevice(admin);
+ if (admin.mSuspendPersonalApps) {
+ return DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY;
+ } else {
+ return DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED;
+ }
+ }
+ }
+
+ @Override
+ public void setPersonalAppsSuspended(ComponentName who, boolean suspended) {
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER,
+ false /* parent */);
+ // DO shouldn't be able to use this method.
+ enforceProfileOwnerOfOrganizationOwnedDevice(admin);
+ if (admin.mSuspendPersonalApps != suspended) {
+ admin.mSuspendPersonalApps = suspended;
+ saveSettingsLocked(callingUserId);
+ }
+ }
+
+ if (getUserData(UserHandle.USER_SYSTEM).mPersonalAppsSuspended == suspended) {
+ // Admin request matches current state, nothing to do.
+ return;
+ }
+
+ suspendPersonalAppsInternal(suspended, UserHandle.USER_SYSTEM);
+
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ if (suspended) {
+ sendPersonalAppsSuspendedNotification(callingUserId);
+ } else {
+ clearPersonalAppsSuspendedNotification(callingUserId);
+ }
+ });
+ }
+
+ private void suspendPersonalAppsInternal(boolean suspended, int userId) {
+ Slog.i(LOG_TAG, String.format("%s personal apps for user %d",
+ suspended ? "Suspending" : "Unsuspending", userId));
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ try {
+ final String[] appsToSuspend =
+ new PersonalAppsSuspensionHelper(mContext, mInjector.getPackageManager())
+ .getPersonalAppsForSuspension(userId);
+ final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser(
+ appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId);
+ if (!ArrayUtils.isEmpty(failedPackages)) {
+ Slog.wtf(LOG_TAG, String.format("Failed to %s packages: %s",
+ suspended ? "suspend" : "unsuspend", String.join(",", failedPackages)));
+ }
+ } catch (RemoteException re) {
+ // Shouldn't happen.
+ Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+ }
+ });
+
+ synchronized (getLockObject()) {
+ getUserData(userId).mPersonalAppsSuspended = suspended;
+ saveSettingsLocked(userId);
+ }
+ }
+
+ private void maybeUpdatePersonalAppsSuspendedNotification(int profileUserId) {
+ // TODO(b/147414651): Unless updated, the notification stops working after turning the
+ // profile off and back on, so it has to be updated more often than necessary.
+ if (getUserData(UserHandle.USER_SYSTEM).mPersonalAppsSuspended
+ && getProfileParentId(profileUserId) == UserHandle.USER_SYSTEM) {
+ sendPersonalAppsSuspendedNotification(profileUserId);
+ }
+ }
+
+ private void clearPersonalAppsSuspendedNotification(int userId) {
+ mInjector.binderWithCleanCallingIdentity(() ->
+ mInjector.getNotificationManager().cancel(
+ SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
+ }
+
+ private void sendPersonalAppsSuspendedNotification(int userId) {
+ final String profileOwnerPackageName;
+ synchronized (getLockObject()) {
+ profileOwnerPackageName = mOwners.getProfileOwnerComponent(userId).getPackageName();
+ }
+
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
+ intent.setPackage(profileOwnerPackageName);
+
+ final PendingIntent pendingIntent = mInjector.pendingIntentGetActivityAsUser(mContext,
+ 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT, null /* options */,
+ UserHandle.of(userId));
+
+ final Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setOngoing(true)
+ .setContentTitle(
+ mContext.getString(
+ R.string.personal_apps_suspended_notification_title))
+ .setContentText(mContext.getString(
+ R.string.personal_apps_suspended_notification_text))
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setContentIntent(pendingIntent)
+ .build();
+ mInjector.getNotificationManager().notify(
+ SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED, notification);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
new file mode 100644
index 000000000000..180acc85e5f6
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -0,0 +1,201 @@
+/*
+ * 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.devicepolicy;
+
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.internal.R;
+import com.android.server.inputmethod.InputMethodManagerInternal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utility class to find what personal apps should be suspended to limit personal device use.
+ */
+public class PersonalAppsSuspensionHelper {
+ private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ public PersonalAppsSuspensionHelper(Context context, PackageManager packageManager) {
+ mContext = context;
+ mPackageManager = packageManager;
+ }
+
+ /**
+ * @return List of packages that should be suspended to limit personal use.
+ */
+ String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
+ final List<PackageInfo> installedPackageInfos =
+ mPackageManager.getInstalledPackagesAsUser(0 /* flags */, userId);
+ final Set<String> result = new HashSet<>();
+ for (final PackageInfo packageInfo : installedPackageInfos) {
+ final ApplicationInfo info = packageInfo.applicationInfo;
+ if ((!info.isSystemApp() && !info.isUpdatedSystemApp())
+ || hasLauncherIntent(packageInfo.packageName)) {
+ result.add(packageInfo.packageName);
+ }
+ }
+ result.removeAll(getCriticalPackages());
+ result.removeAll(getSystemLauncherPackages());
+ result.removeAll(getAccessibilityServices(userId));
+ result.removeAll(getInputMethodPackages(userId));
+ result.remove(getActiveLauncherPackages(userId));
+ result.remove(getDialerPackage(userId));
+ result.remove(getSettingsPackageName(userId));
+
+ Slog.i(LOG_TAG, "Packages subject to suspension: " + String.join(",", result));
+ return result.toArray(new String[0]);
+ }
+
+ private List<String> getSystemLauncherPackages() {
+ final List<String> result = new ArrayList<>();
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final List<ResolveInfo> matchingActivities =
+ mPackageManager.queryIntentActivities(intent, 0);
+ for (final ResolveInfo resolveInfo : matchingActivities) {
+ if (resolveInfo.activityInfo == null
+ || TextUtils.isEmpty(resolveInfo.activityInfo.packageName)) {
+ Slog.wtf(LOG_TAG, "Could not find package name for launcher app" + resolveInfo);
+ continue;
+ }
+ final String packageName = resolveInfo.activityInfo.packageName;
+ try {
+ final ApplicationInfo applicationInfo =
+ mPackageManager.getApplicationInfo(packageName, 0);
+ if (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) {
+ Log.d(LOG_TAG, "Not suspending system launcher package: " + packageName);
+ result.add(packageName);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(LOG_TAG, "Could not find application info for launcher app: " + packageName);
+ }
+ }
+ return result;
+ }
+
+ private List<String> getAccessibilityServices(int userId) {
+ final List<AccessibilityServiceInfo> accessibilityServiceInfos =
+ getAccessibilityManagerForUser(userId)
+ .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
+ final List<String> result = new ArrayList<>();
+ for (final AccessibilityServiceInfo serviceInfo : accessibilityServiceInfos) {
+ final ComponentName componentName =
+ ComponentName.unflattenFromString(serviceInfo.getId());
+ if (componentName != null) {
+ final String packageName = componentName.getPackageName();
+ Slog.d(LOG_TAG, "Not suspending a11y service: " + packageName);
+ result.add(packageName);
+ }
+ }
+ return result;
+ }
+
+ private List<String> getInputMethodPackages(int userId) {
+ final List<InputMethodInfo> enabledImes =
+ InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId);
+ final List<String> result = new ArrayList<>();
+ for (final InputMethodInfo info : enabledImes) {
+ Slog.d(LOG_TAG, "Not suspending IME: " + info.getPackageName());
+ result.add(info.getPackageName());
+ }
+ return result;
+ }
+
+ @Nullable
+ private String getActiveLauncherPackages(int userId) {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ return getPackageNameForIntent("active launcher", intent, userId);
+ }
+
+ @Nullable
+ private String getSettingsPackageName(int userId) {
+ final Intent intent = new Intent(Settings.ACTION_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ return getPackageNameForIntent("settings", intent, userId);
+ }
+
+ @Nullable
+ private String getDialerPackage(int userId) {
+ final Intent intent = new Intent(Intent.ACTION_DIAL);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ return getPackageNameForIntent("dialer", intent, userId);
+ }
+
+ @Nullable
+ private String getPackageNameForIntent(String name, Intent intent, int userId) {
+ final ResolveInfo resolveInfo =
+ mPackageManager.resolveActivityAsUser(intent, /* flags= */ 0, userId);
+ if (resolveInfo != null) {
+ final String packageName = resolveInfo.activityInfo.packageName;
+ Slog.d(LOG_TAG, "Not suspending " + name + " package: " + packageName);
+ return packageName;
+ }
+ return null;
+ }
+
+ private List<String> getCriticalPackages() {
+ final List<String> result = Arrays.asList(mContext.getResources()
+ .getStringArray(R.array.config_packagesExemptFromSuspension));
+ Slog.d(LOG_TAG, "Not suspending critical packages: " + String.join(",", result));
+ return result;
+ }
+
+ private boolean hasLauncherIntent(String packageName) {
+ final Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+ intentToResolve.setPackage(packageName);
+ final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(
+ intentToResolve, PackageManager.GET_UNINSTALLED_PACKAGES);
+ return resolveInfos != null && !resolveInfos.isEmpty();
+ }
+
+ private AccessibilityManager getAccessibilityManagerForUser(int userId) {
+ final IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+ final IAccessibilityManager service =
+ iBinder == null ? null : IAccessibilityManager.Stub.asInterface(iBinder);
+ return new AccessibilityManager(mContext, service, userId);
+ }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index ec56e1ebc8e0..62ff3a1c2126 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -96,6 +96,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.util.FeatureFlagUtils;
import android.util.Pair;
import com.android.internal.backup.IBackupTransport;
@@ -258,6 +259,9 @@ public class KeyValueBackupTaskTest {
public void tearDown() throws Exception {
ShadowBackupDataInput.reset();
ShadowApplicationPackageManager.reset();
+ // False by default.
+ FeatureFlagUtils.setEnabled(
+ mContext, FeatureFlagUtils.BACKUP_NO_KV_DATA_CHANGE_CALLS, false);
}
@Test
@@ -2344,6 +2348,9 @@ public class KeyValueBackupTaskTest {
@Test
public void testRunTask_whenNoDataToBackupOnFirstBackup_doesNotTellTransportOfBackup()
throws Exception {
+ FeatureFlagUtils.setEnabled(
+ mContext, FeatureFlagUtils.BACKUP_NO_KV_DATA_CHANGE_CALLS, true);
+
TransportMock transportMock = setUpInitializedTransport(mTransport);
mBackupManagerService.setCurrentToken(0L);
when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
@@ -2361,6 +2368,9 @@ public class KeyValueBackupTaskTest {
@Test
public void testRunTask_whenBackupHasCompletedAndThenNoDataChanges_transportGetsNotified()
throws Exception {
+ FeatureFlagUtils.setEnabled(
+ mContext, FeatureFlagUtils.BACKUP_NO_KV_DATA_CHANGE_CALLS, true);
+
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
when(transportMock.transport.isAppEligibleForBackup(
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index b3b5af0796ab..0e24b0314b2d 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.MANAGE_APPOPS"/>
+ <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
<application android:testOnly="true"
android:debuggable="true">
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index c3602f8db9bc..2080fdf2e40d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -30,11 +30,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.times;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.VersionedPackage;
+import android.os.Bundle;
import android.os.RecoverySystem;
+import android.os.RemoteCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -44,18 +47,21 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import com.android.server.RescueParty.RescuePartyObserver;
import com.android.server.am.SettingsToPropertiesMapper;
-import com.android.server.utils.FlagNamespaceUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
/**
* Test RescueParty.
@@ -69,16 +75,25 @@ public class RescuePartyTest {
private static VersionedPackage sFailingPackage = new VersionedPackage("com.package.name", 1);
private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
+ private static final String CALLING_PACKAGE1 = "com.package.name1";
+ private static final String CALLING_PACKAGE2 = "com.package.name2";
+ private static final String NAMESPACE1 = "namespace1";
+ private static final String NAMESPACE2 = "namespace2";
private MockitoSession mSession;
+ private HashMap<String, String> mSystemSettingsMap;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mMockContext;
-
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private PackageWatchdog mMockPackageWatchdog;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ContentResolver mMockContentResolver;
- private HashMap<String, String> mSystemSettingsMap;
+ @Captor
+ private ArgumentCaptor<RemoteCallback> mMonitorCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<List<String>> mPackageListCaptor;
@Before
public void setUp() throws Exception {
@@ -90,14 +105,17 @@ public class RescuePartyTest {
.spyStatic(SystemProperties.class)
.spyStatic(Settings.Global.class)
.spyStatic(Settings.Secure.class)
+ .spyStatic(Settings.Config.class)
.spyStatic(SettingsToPropertiesMapper.class)
.spyStatic(RecoverySystem.class)
.spyStatic(RescueParty.class)
+ .spyStatic(PackageWatchdog.class)
.startMocking();
mSystemSettingsMap = new HashMap<>();
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
-
+ // Reset observer instance to get new mock context on every run
+ RescuePartyObserver.reset();
// Mock SystemProperties setter and various getters
doAnswer((Answer<Void>) invocationOnMock -> {
@@ -143,9 +161,11 @@ public class RescuePartyTest {
doAnswer((Answer<Void>) invocationOnMock -> null)
.when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()));
+ // Mock PackageWatchdog
+ doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
+ .when(() -> PackageWatchdog.getInstance(mMockContext));
doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
- FlagNamespaceUtils.resetKnownResetNamespacesFlagCounterForTest();
SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
Integer.toString(RescueParty.LEVEL_NONE));
@@ -162,19 +182,19 @@ public class RescuePartyTest {
public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
@@ -189,19 +209,19 @@ public class RescuePartyTest {
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
notePersistentAppCrash();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
notePersistentAppCrash();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
notePersistentAppCrash();
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
@@ -213,6 +233,54 @@ public class RescuePartyTest {
}
@Test
+ public void testNonPersistentAppCrashDetectionWithScopedResets() {
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+ mMonitorCallbackCaptor.capture()));
+
+ // Record DeviceConfig accesses
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+ // Fake DeviceConfig value changes
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+ verify(mMockPackageWatchdog).startObservingHealth(observer,
+ Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+ verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
+ mPackageListCaptor.capture(),
+ eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
+ assertTrue(mPackageListCaptor.getValue().containsAll(
+ Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
+ // Perform and verify scoped resets
+ final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces);
+ assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+ SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces);
+ assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+ SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/null);
+ assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+ SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
+ verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
+ assertTrue(RescueParty.isAttemptingFactoryReset());
+ }
+
+ @Test
public void testIsAttemptingFactoryReset() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot();
@@ -227,7 +295,7 @@ public class RescuePartyTest {
RescueParty.onSettingsProviderPublished(mMockContext);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@@ -244,15 +312,6 @@ public class RescuePartyTest {
FAKE_NATIVE_NAMESPACE1));
verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
FAKE_NATIVE_NAMESPACE2));
-
- ExtendedMockito.verify(
- () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY,
- FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 0,
- FAKE_NATIVE_NAMESPACE1, /*makeDefault=*/true));
- ExtendedMockito.verify(
- () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY,
- FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 1,
- FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true));
}
@Test
@@ -326,11 +385,19 @@ public class RescuePartyTest {
RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
}
- private void verifySettingsResets(int resetMode) {
+ private void verifySettingsResets(int resetMode, String[] resetNamespaces) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
eq(resetMode), anyInt()));
+ // Verify DeviceConfig resets
+ if (resetNamespaces == null) {
+ verify(() -> DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null));
+ } else {
+ for (String namespace : resetNamespaces) {
+ verify(() -> DeviceConfig.resetToDefaults(resetMode, namespace));
+ }
+ }
}
private void noteBoot() {
@@ -339,6 +406,22 @@ public class RescuePartyTest {
private void notePersistentAppCrash() {
RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
- "com.package.name", 1), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ "com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
+ }
+
+ private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
+ Bundle result = new Bundle();
+ result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, Settings.EXTRA_ACCESS_CALLBACK);
+ result.putString(Settings.EXTRA_CALLING_PACKAGE, callingPackage);
+ result.putString(Settings.EXTRA_NAMESPACE, namespace);
+ return result;
+ }
+
+ private Bundle getConfigNamespaceUpdateBundle(String updatedNamespace) {
+ Bundle result = new Bundle();
+ result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE,
+ Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK);
+ result.putString(Settings.EXTRA_NAMESPACE, updatedNamespace);
+ return result;
}
}
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 8f1d0f7648f5..def5b617becd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2183,6 +2183,63 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
}
+ public void testSetApplicationHiddenWithDO() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ mContext.packageName = admin1.getPackageName();
+ setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
+
+ String packageName = "com.google.android.test";
+
+ dpm.setApplicationHidden(admin1, packageName, true);
+ verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
+ true, UserHandle.USER_SYSTEM);
+
+ dpm.setApplicationHidden(admin1, packageName, false);
+ verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
+ false, UserHandle.USER_SYSTEM);
+
+ verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
+ PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ verify(getServices().ipackageManager, never()).getPackageInfo(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM);
+ }
+
+ public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception {
+ final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
+ final int MANAGED_PROFILE_ADMIN_UID =
+ UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ mContext.packageName = admin1.getPackageName();
+ setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
+
+ String packageName = "com.google.android.test";
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
+ .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+ when(getServices().ipackageManager.getPackageInfo(packageName,
+ PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)).thenReturn(
+ packageInfo);
+ when(getServices().ipackageManager.getPackageInfo(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM)).thenReturn(packageInfo);
+
+ parentDpm.setApplicationHidden(admin1, packageName, true);
+ verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
+ true, UserHandle.USER_SYSTEM);
+
+ parentDpm.setApplicationHidden(admin1, packageName, false);
+ verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName,
+ false, UserHandle.USER_SYSTEM);
+ }
+
public void testGetMacAddress() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
new file mode 100644
index 000000000000..b0def605db79
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.lights;
+
+import static android.hardware.lights.LightsRequest.Builder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.hardware.light.HwLight;
+import android.hardware.light.HwLightState;
+import android.hardware.light.ILights;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.os.Looper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LightsServiceTest {
+
+ private final ILights mHal = new ILights.Stub() {
+ @Override
+ public void setLightState(int id, HwLightState state) {
+ return;
+ }
+
+ @Override
+ public HwLight[] getLights() {
+ return new HwLight[] {
+ fakeHwLight(101, 3, 1),
+ fakeHwLight(102, LightsManager.LIGHT_TYPE_MICROPHONE, 4),
+ fakeHwLight(103, LightsManager.LIGHT_TYPE_MICROPHONE, 3),
+ fakeHwLight(104, LightsManager.LIGHT_TYPE_MICROPHONE, 1),
+ fakeHwLight(105, LightsManager.LIGHT_TYPE_MICROPHONE, 2)
+ };
+ }
+ };
+
+ private static HwLight fakeHwLight(int id, int type, int ordinal) {
+ HwLight light = new HwLight();
+ light.id = id;
+ light.type = (byte) type;
+ light.ordinal = ordinal;
+ return light;
+ }
+
+ @Mock
+ Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testGetLights_filtersSystemLights() {
+ LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+ LightsManager manager = new LightsManager(mContext, service.mManagerService);
+
+ // When lights are listed, only the 4 MICROPHONE lights should be visible.
+ assertThat(manager.getLights().size()).isEqualTo(4);
+ }
+
+ @Test
+ public void testControlMultipleLights() {
+ LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+ LightsManager manager = new LightsManager(mContext, service.mManagerService);
+
+ // When the session requests to turn 3/4 lights on:
+ LightsManager.LightsSession session = manager.openSession();
+ session.setLights(new Builder()
+ .setLight(manager.getLights().get(0), new LightState(0xf1))
+ .setLight(manager.getLights().get(1), new LightState(0xf2))
+ .setLight(manager.getLights().get(2), new LightState(0xf3))
+ .build());
+
+ // Then all 3 should turn on.
+ assertThat(manager.getLightState(manager.getLights().get(0)).getColor()).isEqualTo(0xf1);
+ assertThat(manager.getLightState(manager.getLights().get(1)).getColor()).isEqualTo(0xf2);
+ assertThat(manager.getLightState(manager.getLights().get(2)).getColor()).isEqualTo(0xf3);
+
+ // And the 4th should remain off.
+ assertThat(manager.getLightState(manager.getLights().get(3)).getColor()).isEqualTo(0x00);
+ }
+
+ @Test
+ public void testControlLights_onlyEffectiveForLifetimeOfClient() {
+ LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+ LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ Light micLight = manager.getLights().get(0);
+
+ // The light should begin by being off.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+
+ // When a session commits changes:
+ LightsManager.LightsSession session = manager.openSession();
+ session.setLights(new Builder().setLight(micLight, new LightState(0xff00ff00)).build());
+ // Then the light should turn on.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff00ff00);
+
+ // When the session goes away:
+ session.close();
+ // Then the light should turn off.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+ }
+
+ @Test
+ public void testControlLights_firstCallerWinsContention() {
+ LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+ LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ Light micLight = manager.getLights().get(0);
+
+ LightsManager.LightsSession session1 = manager.openSession();
+ LightsManager.LightsSession session2 = manager.openSession();
+
+ // When session1 and session2 both request the same light:
+ session1.setLights(new Builder().setLight(micLight, new LightState(0xff0000ff)).build());
+ session2.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+ // Then session1 should win because it was created first.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff0000ff);
+
+ // When session1 goes away:
+ session1.close();
+ // Then session2 should have its request go into effect.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xffffffff);
+
+ // When session2 goes away:
+ session2.close();
+ // Then the light should turn off because there are no more sessions.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
+ }
+
+ @Test
+ public void testClearLight() {
+ LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
+ LightsManager manager = new LightsManager(mContext, service.mManagerService);
+ Light micLight = manager.getLights().get(0);
+
+ // When the session turns a light on:
+ LightsManager.LightsSession session = manager.openSession();
+ session.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+
+ // And then the session clears it again:
+ session.setLights(new Builder().clearLight(micLight).build());
+
+ // Then the light should turn back off.
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
+ }
+}
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 355cadaa1de8..a1baf0e9ce05 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -138,6 +138,7 @@ import android.util.Range;
import android.util.RecurrenceRule;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -1055,6 +1056,7 @@ public class NetworkPolicyManagerServiceTest {
computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
}
+ @FlakyTest
@Test
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
NetworkState[] state = null;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 15327b6e5463..a8674a8f8be4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -309,6 +309,7 @@ public class PackageInstallerSessionTest {
actual.getStagedSessionErrorMessage());
assertEquals(expected.isPrepared(), actual.isPrepared());
assertEquals(expected.isCommitted(), actual.isCommitted());
+ assertEquals(expected.createdMillis, actual.createdMillis);
assertEquals(expected.isSealed(), actual.isSealed());
assertEquals(expected.isMultiPackage(), actual.isMultiPackage());
assertEquals(expected.hasParentSessionId(), actual.hasParentSessionId());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 1e55b1521956..587cfbf062fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -74,7 +74,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.IntPair;
import com.android.server.UiServiceTestCase;
-import com.android.server.lights.Light;
+import com.android.server.lights.LogicalLight;
import org.junit.Before;
import org.junit.Test;
@@ -91,7 +91,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
@Mock AudioManager mAudioManager;
@Mock Vibrator mVibrator;
@Mock android.media.IRingtonePlayer mRingtonePlayer;
- @Mock Light mLight;
+ @Mock LogicalLight mLight;
@Mock
NotificationManagerService.WorkerHandler mHandler;
@Mock
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9260fbf97b86..93e09dfb3f57 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -153,8 +153,8 @@ import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiServiceTestCase;
-import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.lights.LogicalLight;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -372,7 +372,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
});
when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
final LightsManager mockLightsManager = mock(LightsManager.class);
- when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
+ when(mockLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 0527561880f2..5ba676d1c544 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -36,7 +36,6 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -141,7 +140,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
public void layoutWindowLw_fitStatusBars() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.statusBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -159,7 +158,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
public void layoutWindowLw_fitNavigationBars() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.navigationBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.navigationBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -178,7 +177,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -197,7 +196,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
mWindow.mAttrs.privateFlags = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -216,8 +215,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
mWindow.mAttrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.privateFlags = PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.systemBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -235,7 +233,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
public void layoutWindowLw_fitAllSides() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
- mWindow.mAttrs.setFitWindowInsetsSides(Side.all());
+ mWindow.mAttrs.setFitInsetsSides(Side.all());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -253,7 +251,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
public void layoutWindowLw_fitTopOnly() {
assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
- mWindow.mAttrs.setFitWindowInsetsSides(Side.TOP);
+ mWindow.mAttrs.setFitInsetsSides(Side.TOP);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -275,7 +273,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow);
state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
- mWindow.mAttrs.setFitIgnoreVisibility(true);
+ mWindow.mAttrs.setFitInsetsIgnoringVisibility(true);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -297,7 +295,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow);
state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
- mWindow.mAttrs.setFitIgnoreVisibility(false);
+ mWindow.mAttrs.setFitInsetsIgnoringVisibility(false);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -374,7 +372,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- mWindow.mAttrs.setFitWindowInsetsTypes(0 /* types */);
+ mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
@@ -431,8 +429,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mWindow.mAttrs.setFitWindowInsetsTypes(
- mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
+ mWindow.mAttrs.setFitInsetsTypes(
+ mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -537,8 +535,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mWindow.mAttrs.setFitWindowInsetsTypes(
- mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
+ mWindow.mAttrs.setFitInsetsTypes(
+ mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -556,7 +554,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
addDisplayCutout();
mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
- mWindow.mAttrs.setFitWindowInsetsTypes(Type.systemBars() & ~Type.statusBars());
+ mWindow.mAttrs.setFitInsetsTypes(Type.systemBars() & ~Type.statusBars());
mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
mWindow.mAttrs.width = DISPLAY_WIDTH;
mWindow.mAttrs.height = DISPLAY_HEIGHT;
@@ -577,8 +575,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mWindow.mAttrs.setFitWindowInsetsTypes(
- mWindow.mAttrs.getFitWindowInsetsTypes() & ~Type.statusBars());
+ mWindow.mAttrs.setFitInsetsTypes(
+ mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindow(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index e699b526e848..c370d6c7c516 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -28,6 +28,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -233,6 +234,16 @@ public class DisplayPolicyTests extends WindowTestsBase {
assertNotEquals(0, toast.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED);
}
+ @Test(expected = RuntimeException.class)
+ public void testMainAppWindowDisallowFitSystemWindowTypes() {
+ final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+ final WindowState activity = createBaseApplicationWindow();
+ activity.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+
+ policy.adjustWindowParamsLw(activity, activity.mAttrs, 0 /* callingPid */,
+ 0 /* callingUid */);
+ }
+
private WindowState createToastWindow() {
final WindowState win = createWindow(null, TYPE_TOAST, "Toast");
final WindowManager.LayoutParams attrs = win.mAttrs;
@@ -254,6 +265,17 @@ public class DisplayPolicyTests extends WindowTestsBase {
return win;
}
+ private WindowState createBaseApplicationWindow() {
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "Application");
+ final WindowManager.LayoutParams attrs = win.mAttrs;
+ attrs.width = MATCH_PARENT;
+ attrs.height = MATCH_PARENT;
+ attrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ attrs.format = PixelFormat.OPAQUE;
+ win.mHasSurface = true;
+ return win;
+ }
+
@Test
@FlakyTest(bugId = 131005232)
public void testOverlappingWithNavBar() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b8cd37860284..5119e5824f7f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -369,7 +369,7 @@ public class UsageStatsService extends SystemService implements
/**
* Fetches a map (package_name:install_time) of installed packages for the given user. This
* map contains all installed packages, including those packages which have been uninstalled
- * with the DONT_DELETE_DATA flag.
+ * with the DELETE_KEEP_DATA flag.
* This is a helper method which should only be called when the given user's usage stats service
* is initialized; it performs a heavy query to package manager so do not call it otherwise.
* <br/>
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index c58b6da64baa..af81ab6339f3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -46,18 +46,21 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private static final String NAME = "sound_model.db";
private static final int VERSION = 7;
- public static interface SoundModelContract {
- public static final String TABLE = "sound_model";
- public static final String KEY_MODEL_UUID = "model_uuid";
- public static final String KEY_VENDOR_UUID = "vendor_uuid";
- public static final String KEY_KEYPHRASE_ID = "keyphrase_id";
- public static final String KEY_TYPE = "type";
- public static final String KEY_DATA = "data";
- public static final String KEY_RECOGNITION_MODES = "recognition_modes";
- public static final String KEY_LOCALE = "locale";
- public static final String KEY_HINT_TEXT = "hint_text";
- public static final String KEY_USERS = "users";
- public static final String KEY_MODEL_VERSION = "model_version";
+ /**
+ * Keyphrase sound model database columns
+ */
+ public interface SoundModelContract {
+ String TABLE = "sound_model";
+ String KEY_MODEL_UUID = "model_uuid";
+ String KEY_VENDOR_UUID = "vendor_uuid";
+ String KEY_KEYPHRASE_ID = "keyphrase_id";
+ String KEY_TYPE = "type";
+ String KEY_DATA = "data";
+ String KEY_RECOGNITION_MODES = "recognition_modes";
+ String KEY_LOCALE = "locale";
+ String KEY_HINT_TEXT = "hint_text";
+ String KEY_USERS = "users";
+ String KEY_MODEL_VERSION = "model_version";
}
// Table Create Statement
@@ -173,7 +176,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
soundModel.keyphrases[0].recognitionModes);
values.put(SoundModelContract.KEY_USERS,
getCommaSeparatedString(soundModel.keyphrases[0].users));
- values.put(SoundModelContract.KEY_LOCALE, soundModel.keyphrases[0].locale);
+ values.put(SoundModelContract.KEY_LOCALE,
+ soundModel.keyphrases[0].locale.toLanguageTag());
values.put(SoundModelContract.KEY_HINT_TEXT, soundModel.keyphrases[0].text);
try {
return db.insertWithOnConflict(SoundModelContract.TABLE, null, values,
@@ -190,7 +194,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
* Deletes the sound model and associated keyphrases.
*/
public boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) {
- // Sanitize the locale to guard against SQL injection.
+ // Normalize the locale to guard against SQL injection.
bcp47Locale = Locale.forLanguageTag(bcp47Locale).toLanguageTag();
synchronized(this) {
KeyphraseSoundModel soundModel = getKeyphraseSoundModel(keyphraseId, userHandle,
@@ -226,90 +230,117 @@ public class DatabaseHelper extends SQLiteOpenHelper {
String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE
+ " WHERE " + SoundModelContract.KEY_KEYPHRASE_ID + "= '" + keyphraseId
+ "' AND " + SoundModelContract.KEY_LOCALE + "='" + bcp47Locale + "'";
- SQLiteDatabase db = getReadableDatabase();
- Cursor c = db.rawQuery(selectQuery, null);
+ return getValidKeyphraseSoundModelForUser(selectQuery, userHandle);
+ }
+ }
- try {
- if (c.moveToFirst()) {
- do {
- int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
- if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
- if (DBG) {
- Slog.w(TAG, "Ignoring SoundModel since it's type is incorrect");
- }
- continue;
- }
+ /**
+ * Returns a matching {@link KeyphraseSoundModel} for the keyphrase string.
+ * Returns null if a match isn't found.
+ *
+ * TODO: We only support one keyphrase currently.
+ */
+ public KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle,
+ String bcp47Locale) {
+ // Sanitize the locale to guard against SQL injection.
+ bcp47Locale = Locale.forLanguageTag(bcp47Locale).toLanguageTag();
+ synchronized (this) {
+ // Find the corresponding sound model ID for the keyphrase.
+ String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE
+ + " WHERE " + SoundModelContract.KEY_HINT_TEXT + "= '" + keyphrase
+ + "' AND " + SoundModelContract.KEY_LOCALE + "='" + bcp47Locale + "'";
+ return getValidKeyphraseSoundModelForUser(selectQuery, userHandle);
+ }
+ }
- String modelUuid = c.getString(
- c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
- if (modelUuid == null) {
- Slog.w(TAG, "Ignoring SoundModel since it doesn't specify an ID");
- continue;
- }
+ private KeyphraseSoundModel getValidKeyphraseSoundModelForUser(String selectQuery,
+ int userHandle) {
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor c = db.rawQuery(selectQuery, null);
- String vendorUuidString = null;
- int vendorUuidColumn = c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID);
- if (vendorUuidColumn != -1) {
- vendorUuidString = c.getString(vendorUuidColumn);
- }
- byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
- int recognitionModes = c.getInt(
- c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
- int[] users = getArrayForCommaSeparatedString(
- c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS)));
- String modelLocale = c.getString(
- c.getColumnIndex(SoundModelContract.KEY_LOCALE));
- String text = c.getString(
- c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
- int version = c.getInt(
- c.getColumnIndex(SoundModelContract.KEY_MODEL_VERSION));
-
- // Only add keyphrases meant for the current user.
- if (users == null) {
- // No users present in the keyphrase.
- Slog.w(TAG, "Ignoring SoundModel since it doesn't specify users");
- continue;
+ try {
+ if (c.moveToFirst()) {
+ do {
+ int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
+ if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
+ if (DBG) {
+ Slog.w(TAG, "Ignoring SoundModel since its type is incorrect");
}
+ continue;
+ }
- boolean isAvailableForCurrentUser = false;
- for (int user : users) {
- if (userHandle == user) {
- isAvailableForCurrentUser = true;
- break;
- }
- }
- if (!isAvailableForCurrentUser) {
- if (DBG) {
- Slog.w(TAG, "Ignoring SoundModel since user handles don't match");
- }
- continue;
- } else {
- if (DBG) Slog.d(TAG, "Found a SoundModel for user: " + userHandle);
- }
+ String modelUuid = c.getString(
+ c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
+ if (modelUuid == null) {
+ Slog.w(TAG, "Ignoring SoundModel since it doesn't specify an ID");
+ continue;
+ }
+
+ String vendorUuidString = null;
+ int vendorUuidColumn = c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID);
+ if (vendorUuidColumn != -1) {
+ vendorUuidString = c.getString(vendorUuidColumn);
+ }
+ int keyphraseId = c.getInt(
+ c.getColumnIndex(SoundModelContract.KEY_KEYPHRASE_ID));
+ byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
+ int recognitionModes = c.getInt(
+ c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
+ int[] users = getArrayForCommaSeparatedString(
+ c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS)));
+ Locale modelLocale = Locale.forLanguageTag(c.getString(
+ c.getColumnIndex(SoundModelContract.KEY_LOCALE)));
+ String text = c.getString(
+ c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
+ int version = c.getInt(
+ c.getColumnIndex(SoundModelContract.KEY_MODEL_VERSION));
+
+ // Only add keyphrases meant for the current user.
+ if (users == null) {
+ // No users present in the keyphrase.
+ Slog.w(TAG, "Ignoring SoundModel since it doesn't specify users");
+ continue;
+ }
- Keyphrase[] keyphrases = new Keyphrase[1];
- keyphrases[0] = new Keyphrase(
- keyphraseId, recognitionModes, modelLocale, text, users);
- UUID vendorUuid = null;
- if (vendorUuidString != null) {
- vendorUuid = UUID.fromString(vendorUuidString);
+ boolean isAvailableForCurrentUser = false;
+ for (int user : users) {
+ if (userHandle == user) {
+ isAvailableForCurrentUser = true;
+ break;
}
- KeyphraseSoundModel model = new KeyphraseSoundModel(
- UUID.fromString(modelUuid), vendorUuid, data, keyphrases, version);
+ }
+ if (!isAvailableForCurrentUser) {
if (DBG) {
- Slog.d(TAG, "Found SoundModel for the given keyphrase/locale/user: "
- + model);
+ Slog.w(TAG, "Ignoring SoundModel since user handles don't match");
}
- return model;
- } while (c.moveToNext());
- }
- Slog.w(TAG, "No SoundModel available for the given keyphrase");
- } finally {
- c.close();
- db.close();
+ continue;
+ } else {
+ if (DBG) Slog.d(TAG, "Found a SoundModel for user: " + userHandle);
+ }
+
+ Keyphrase[] keyphrases = new Keyphrase[1];
+ keyphrases[0] = new Keyphrase(
+ keyphraseId, recognitionModes, modelLocale, text, users);
+ UUID vendorUuid = null;
+ if (vendorUuidString != null) {
+ vendorUuid = UUID.fromString(vendorUuidString);
+ }
+ KeyphraseSoundModel model = new KeyphraseSoundModel(
+ UUID.fromString(modelUuid), vendorUuid, data, keyphrases, version);
+ if (DBG) {
+ Slog.d(TAG, "Found SoundModel for the given keyphrase/locale/user: "
+ + model);
+ }
+ return model;
+ } while (c.moveToNext());
}
- return null;
+ Slog.w(TAG, "No SoundModel available for the given keyphrase");
+ } finally {
+ c.close();
+ db.close();
}
+
+ return null;
}
private static String getCommaSeparatedString(int[] users) {
@@ -431,8 +462,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
}
}
+ /**
+ * Dumps contents of database for dumpsys
+ */
public void dump(PrintWriter pw) {
- synchronized(this) {
+ synchronized (this) {
String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE;
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 506c67e12528..d5eec332cda0 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,7 +41,9 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.ModelParams;
+import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
@@ -90,6 +92,7 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -923,6 +926,8 @@ public class VoiceInteractionManagerService extends SystemService {
}
//----------------- Model management APIs --------------------------------//
+ // TODO: add check to only allow active voice interaction service or keyphrase enrollment
+ // application to manage voice models
@Override
public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
@@ -1022,6 +1027,41 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Nullable
+ public KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service,
+ String keyphrase, String bcp47Locale) {
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ if (bcp47Locale == null) {
+ throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
+ }
+
+ final int callingUid = UserHandle.getCallingUserId();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ KeyphraseSoundModel model =
+ mDbHelper.getKeyphraseSoundModel(keyphrase, callingUid, bcp47Locale);
+ if (model == null) {
+ return null;
+ }
+
+ for (SoundTrigger.Keyphrase phrase : model.keyphrases) {
+ if (keyphrase.equals(phrase.text)) {
+ ArraySet<Locale> locales = new ArraySet<>();
+ locales.add(phrase.locale);
+ return new KeyphraseMetadata(phrase.id, phrase.text, locales,
+ phrase.recognitionModes);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+
+ return null;
+ }
+
@Override
public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
// Allow the call if this is the current voice interaction service.
diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
index 4a50e98e527e..4a81a8eea5cf 100644
--- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
+++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
@@ -35,8 +36,6 @@ import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.ArrayList;
import java.util.List;
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 58a7ea08da3f..628c48070314 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,18 +1,16 @@
set noparent
-tgunn@google.com
-breadley@google.com
-hallliu@google.com
-rgreenwalt@google.com
-mpq@google.com
amitmahajan@google.com
+breadley@google.com
fionaxu@google.com
jackyu@google.com
+hallliu@google.com
+rgreenwalt@google.com
+tgunn@google.com
jminjie@google.com
-satk@google.com
shuoq@google.com
refuhoo@google.com
-paulye@google.com
nazaninb@google.com
sarahchin@google.com
dbright@google.com
+xiaotonj@google.com
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 9b8282806c3c..32f9d53e59f8 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -20,6 +20,7 @@ import android.Manifest.permission;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -40,7 +41,6 @@ import android.os.UserHandle;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.telephony.PackageChangeReceiver;
-import android.util.Log;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -48,8 +48,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -205,7 +203,7 @@ public final class SmsApplication {
< android.os.Process.FIRST_APPLICATION_UID) {
return contextUserId;
} else {
- return UserHandle.getUserId(callingUid);
+ return UserHandle.getUserHandleForUid(callingUid).getIdentifier();
}
}
@@ -811,10 +809,10 @@ public final class SmsApplication {
// This should never happen in prod -- unit tests will put the receiver into a
// unusual state where the pending result is null, which produces a NPE when calling
// getSendingUserId. Just pretend like it's the system user for testing.
- userId = UserHandle.USER_SYSTEM;
+ userId = UserHandle.SYSTEM.getIdentifier();
}
Context userContext = mContext;
- if (userId != UserHandle.USER_SYSTEM) {
+ if (userId != UserHandle.SYSTEM.getIdentifier()) {
try {
userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
UserHandle.of(userId));
diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java
index 12e4b7e26e1e..4a971dd34c8f 100644
--- a/telephony/common/com/google/android/mms/ContentType.java
+++ b/telephony/common/com/google/android/mms/ContentType.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
index 2836c3075b3b..55087ff0fb1d 100644
--- a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
+++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* Thrown when an invalid header value was set.
diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java
index 5be33ed1fac9..24bceb37f590 100644
--- a/telephony/common/com/google/android/mms/MmsException.java
+++ b/telephony/common/com/google/android/mms/MmsException.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A generic exception that is thrown by the Mms client.
diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
index ae447d7a7417..8693385bb032 100644
--- a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
+++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java
index 483fa7f9842e..0d6a46a59fcc 100644
--- a/telephony/common/com/google/android/mms/pdu/Base64.java
+++ b/telephony/common/com/google/android/mms/pdu/Base64.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class Base64 {
/**
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
index 27da35e2d928..5172b7b67f88 100644
--- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
index 7093ac63338c..8fb6a7545abf 100644
--- a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
+++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
index 41662750842f..8c0380f77cdd 100644
--- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
index ebf16ac7e632..320b13ffed2b 100644
--- a/telephony/common/com/google/android/mms/pdu/GenericPdu.java
+++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
index e108f7600baf..42a89c69e873 100644
--- a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
+++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
index b561bd4ab3a7..ca4615c2e9fe 100644
--- a/telephony/common/com/google/android/mms/pdu/NotificationInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
index 3c70f86a0890..ebd81afc0173 100644
--- a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java
index 51914e4110b0..f7f285f653b9 100644
--- a/telephony/common/com/google/android/mms/pdu/PduBody.java
+++ b/telephony/common/com/google/android/mms/pdu/PduBody.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.HashMap;
import java.util.Map;
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
index e24bf21a11b5..b8b212c493aa 100644
--- a/telephony/common/com/google/android/mms/pdu/PduComposer.java
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -17,12 +17,11 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
import android.text.TextUtils;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
index 8551b2f9b693..57141fedf1e0 100644
--- a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
+++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class PduContentTypes {
/**
diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
index b5244645fda1..3e6218480dc5 100644
--- a/telephony/common/com/google/android/mms/pdu/PduHeaders.java
+++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index f48399410723..5340245ae869 100755
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.ContentType;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java
index 09b775118dc3..8dd976b2569f 100644
--- a/telephony/common/com/google/android/mms/pdu/PduPart.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPart.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
import java.util.Map;
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index 8efca0ea3909..fcd5b8ff57a8 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -17,6 +17,7 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -40,8 +41,6 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.ContentType;
import com.google.android.mms.InvalidHeaderValueException;
import com.google.android.mms.MmsException;
diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
index 9d6535c72e90..4e1d7f5775ec 100644
--- a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
+++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.ByteArrayOutputStream;
diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
index e38c62dde622..4ba3c71580e0 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
index 9696bc259d00..37ccfb9c9b9b 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
index 03755af4189c..260adfc093f2 100644
--- a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
+++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java
index b85982791ada..779923801bfa 100644
--- a/telephony/common/com/google/android/mms/pdu/SendConf.java
+++ b/telephony/common/com/google/android/mms/pdu/SendConf.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java
index c1b7f934c0f7..6e2f2da01791 100644
--- a/telephony/common/com/google/android/mms/pdu/SendReq.java
+++ b/telephony/common/com/google/android/mms/pdu/SendReq.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.InvalidHeaderValueException;
public class SendReq extends MultimediaMessagePdu {
diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java
index ab5d48a4ce3d..25862e73581e 100644
--- a/telephony/common/com/google/android/mms/util/AbstractCache.java
+++ b/telephony/common/com/google/android/mms/util/AbstractCache.java
@@ -17,10 +17,9 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
public abstract class AbstractCache<K, V> {
diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
index 118de465a518..0f9390daa725 100644
--- a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
+++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
@@ -17,12 +17,11 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.drm.DrmManagerClient;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
public class DownloadDrmHelper {
private static final String TAG = "DownloadDrmHelper";
diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
index 0e8ec91f4ef6..156c7ad8baac 100644
--- a/telephony/common/com/google/android/mms/util/DrmConvertSession.java
+++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
@@ -16,14 +16,13 @@
*/
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.drm.DrmConvertedStatus;
import android.drm.DrmManagerClient;
import android.provider.Downloads;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java
index 94e38946f632..c380d6b3e30f 100644
--- a/telephony/common/com/google/android/mms/util/PduCache.java
+++ b/telephony/common/com/google/android/mms/util/PduCache.java
@@ -17,14 +17,13 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentUris;
import android.content.UriMatcher;
import android.net.Uri;
import android.provider.Telephony.Mms;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
import java.util.HashSet;
diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
index 1ecd1bf93e7f..a4a25d2471ff 100644
--- a/telephony/common/com/google/android/mms/util/PduCacheEntry.java
+++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
@@ -17,7 +17,7 @@
package com.google.android.mms.util;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.pdu.GenericPdu;
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index d030246ed32a..4871434ebc31 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -18,6 +18,7 @@
package com.google.android.mms.util;
import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -27,8 +28,6 @@ import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
public final class SqliteWrapper {
private static final String TAG = "SqliteWrapper";
private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index ef11f469d9a0..93155865c166 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -31,7 +31,9 @@ import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
+import android.telephony.euicc.EuiccManager;
import android.telephony.euicc.EuiccManager.OtaStatus;
+import android.text.TextUtils;
import android.util.Log;
import java.io.PrintWriter;
@@ -311,6 +313,65 @@ public abstract class EuiccService extends Service {
mStubWrapper = new IEuiccServiceWrapper();
}
+ /**
+ * Given a SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2), encode it to
+ * the format described in
+ * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}
+ *
+ * @param subjectCode SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2)
+ * @param reasonCode ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2)
+ * @return encoded error code described in
+ * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE}
+ * @throws NumberFormatException when the Subject/Reason code contains non digits
+ * @throws IllegalArgumentException when Subject/Reason code is null/empty
+ * @throws UnsupportedOperationException when sections has more than four layers (e.g 5.8.1.2)
+ * or when an number is bigger than 15
+ */
+ public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode,
+ @Nullable String reasonCode)
+ throws NumberFormatException, IllegalArgumentException, UnsupportedOperationException {
+ final int maxSupportedSection = 3;
+ final int maxSupportedDigit = 15;
+ final int bitsPerSection = 4;
+
+ if (TextUtils.isEmpty(subjectCode) || TextUtils.isEmpty(reasonCode)) {
+ throw new IllegalArgumentException("SubjectCode/ReasonCode is empty");
+ }
+
+ final String[] subjectCodeToken = subjectCode.split("\\.");
+ final String[] reasonCodeToken = reasonCode.split("\\.");
+
+ if (subjectCodeToken.length > maxSupportedSection
+ || reasonCodeToken.length > maxSupportedSection) {
+ throw new UnsupportedOperationException("Only three nested layer is supported.");
+ }
+
+ int result = EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE;
+
+ // Pad the 0s needed for subject code
+ result = result << (maxSupportedSection - subjectCodeToken.length) * bitsPerSection;
+
+ for (String digitString : subjectCodeToken) {
+ int num = Integer.parseInt(digitString);
+ if (num > maxSupportedDigit) {
+ throw new UnsupportedOperationException("SubjectCode exceeds " + maxSupportedDigit);
+ }
+ result = (result << bitsPerSection) + num;
+ }
+
+ // Pad the 0s needed for reason code
+ result = result << (maxSupportedSection - reasonCodeToken.length) * bitsPerSection;
+ for (String digitString : reasonCodeToken) {
+ int num = Integer.parseInt(digitString);
+ if (num > maxSupportedDigit) {
+ throw new UnsupportedOperationException("ReasonCode exceeds " + maxSupportedDigit);
+ }
+ result = (result << bitsPerSection) + num;
+ }
+
+ return result;
+ }
+
@Override
@CallSuper
public void onCreate() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 822e55b29f76..b30f5868cc63 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1454,6 +1454,50 @@ public class CarrierConfigManager {
"apn_settings_default_apn_types_string_array";
/**
+ * Configs used for APN setup.
+ */
+ public static final class Apn {
+ /** Prefix of all Apn.KEY_* constants. */
+ public static final String KEY_PREFIX = "apn.";
+
+ /** IPv4 internet protocol */
+ public static final String PROTOCOL_IPV4 = "IP";
+ /** IPv6 internet protocol */
+ public static final String PROTOCOL_IPV6 = "IPV6";
+ /** IPv4 or IPv6 internet protocol */
+ public static final String PROTOCOL_IPV4V6 = "IPV4V6";
+
+ /**
+ * Default value of APN protocol field if not specified by user when adding/modifying
+ * an APN.
+ *
+ * Available options are: {@link #PROTOCOL_IPV4}, {@link #PROTOCOL_IPV6},
+ * {@link #PROTOCOL_IPV4V6}
+ */
+ public static final String KEY_SETTINGS_DEFAULT_PROTOCOL_STRING =
+ KEY_PREFIX + "settings_default_protocol_string";
+
+ /**
+ * Default value of APN roaming protocol field if not specified by user when
+ * adding/modifying an APN.
+ *
+ * Available options are: {@link #PROTOCOL_IPV4}, {@link #PROTOCOL_IPV6},
+ * {@link #PROTOCOL_IPV4V6}
+ */
+ public static final String KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING =
+ KEY_PREFIX + "settings_default_roaming_protocol_string";
+
+ private Apn() {}
+
+ private static PersistableBundle getDefaults() {
+ PersistableBundle defaults = new PersistableBundle();
+ defaults.putString(KEY_SETTINGS_DEFAULT_PROTOCOL_STRING, "");
+ defaults.putString(KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING, "");
+ return defaults;
+ }
+ }
+
+ /**
* Boolean indicating if intent for emergency call state changes should be broadcast
* @hide
*/
@@ -3420,6 +3464,14 @@ public class CarrierConfigManager {
"prevent_clir_activation_and_deactivation_code_bool";
/**
+ * Flag specifying whether to show forwarded number on call-in-progress screen.
+ * When true, forwarded number is shown.
+ * When false, forwarded number is not shown.
+ */
+ public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL =
+ "show_forwarded_number_bool";
+
+ /**
* Configs used for epdg tunnel bring up.
*
* @see <a href="https://tools.ietf.org/html/rfc7296">RFC 7296, Internet Key Exchange
@@ -3903,6 +3955,8 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_READ_ONLY_APN_TYPES_STRING_ARRAY, new String[] {"dun"});
sDefaults.putStringArray(KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY, null);
+ sDefaults.putAll(Apn.getDefaults());
+
sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
@@ -4274,6 +4328,7 @@ public class CarrierConfigManager {
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
+ sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
sDefaults.putAll(Iwlan.getDefaults());
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 560c895d7b27..cf8fe6a3c345 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -209,6 +209,19 @@ public final class CellIdentityLte extends CellIdentity {
}
/**
+ * Get bands of the cell
+ *
+ * Reference: 3GPP TS 36.101 section 5.5
+ *
+ * @return List of band number or empty list if not available.
+ */
+ @NonNull
+ public List<Integer> getBands() {
+ // Todo: Add actual support
+ return Collections.emptyList();
+ }
+
+ /**
* @return Cell bandwidth in kHz,
* {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
*/
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 40927a13919a..d4f181fc735a 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -23,6 +23,7 @@ import android.os.Parcel;
import android.telephony.AccessNetworkConstants.NgranBands.NgranBand;
import android.telephony.gsm.GsmCellLocation;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -42,7 +43,7 @@ public final class CellIdentityNr extends CellIdentity {
private final int mPci;
private final int mTac;
private final long mNci;
- private final int mBand;
+ private final List<Integer> mBands;
// a list of additional PLMN-IDs reported for this cell
private final List<String> mAdditionalPlmns;
@@ -52,7 +53,7 @@ public final class CellIdentityNr extends CellIdentity {
* @param pci Physical Cell Id in range [0, 1007].
* @param tac 16-bit Tracking Area Code.
* @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
- * @param band Band number defined in 3GPP TS 38.101-1 and TS 38.101-2.
+ * @param bands Bands used by the cell. Band number defined in 3GPP TS 38.101-1 and TS 38.101-2.
* @param mccStr 3-digit Mobile Country Code in string format.
* @param mncStr 2 or 3-digit Mobile Network Code in string format.
* @param nci The 36-bit NR Cell Identity in range [0, 68719476735].
@@ -62,28 +63,28 @@ public final class CellIdentityNr extends CellIdentity {
*
* @hide
*/
- public CellIdentityNr(int pci, int tac, int nrArfcn, @NgranBand int band, String mccStr,
- String mncStr, long nci, String alphal, String alphas, List<String> additionalPlmns) {
+ public CellIdentityNr(int pci, int tac, int nrArfcn, @NgranBand List<Integer> bands,
+ String mccStr, String mncStr, long nci, String alphal, String alphas,
+ List<String> additionalPlmns) {
super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN);
- mBand = inRangeOrUnavailable(band, AccessNetworkConstants.NgranBands.BAND_1,
- AccessNetworkConstants.NgranBands.BAND_261);
+ mBands = new ArrayList<>(bands);
mNci = inRangeOrUnavailable(nci, 0, MAX_NCI);
- mAdditionalPlmns = additionalPlmns;
+ mAdditionalPlmns = new ArrayList<>(additionalPlmns);
}
/** @hide */
public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) {
- this(cid.pci, cid.tac, cid.nrarfcn, 0, cid.mcc, cid.mnc, cid.nci,
+ this(cid.pci, cid.tac, cid.nrarfcn, Collections.emptyList(), cid.mcc, cid.mnc, cid.nci,
cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
Collections.emptyList());
}
/** @hide */
public CellIdentityNr(android.hardware.radio.V1_5.CellIdentityNr cid) {
- this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, cid.band, cid.base.mcc, cid.base.mnc,
+ this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, cid.bands, cid.base.mcc, cid.base.mnc,
cid.base.nci, cid.base.operatorNames.alphaLong,
cid.base.operatorNames.alphaShort, cid.additionalPlmns);
}
@@ -92,7 +93,7 @@ public final class CellIdentityNr extends CellIdentity {
@Override
public @NonNull CellIdentityNr sanitizeLocationInfo() {
return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn,
- mBand, mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort,
+ mBands, mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort,
mAdditionalPlmns);
}
@@ -109,7 +110,7 @@ public final class CellIdentityNr extends CellIdentity {
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), mPci, mTac,
- mNrArfcn, mBand, mNci, mAdditionalPlmns.hashCode());
+ mNrArfcn, mBands.hashCode(), mNci, mAdditionalPlmns.hashCode());
}
@Override
@@ -120,7 +121,7 @@ public final class CellIdentityNr extends CellIdentity {
CellIdentityNr o = (CellIdentityNr) other;
return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn
- && mBand == o.mBand && mNci == o.mNci
+ && mBands.equals(o.mBands) && mNci == o.mNci
&& mAdditionalPlmns.equals(o.mAdditionalPlmns);
}
@@ -148,16 +149,17 @@ public final class CellIdentityNr extends CellIdentity {
}
/**
- * Get band of the cell
+ * Get bands of the cell
*
* Reference: TS 38.101-1 table 5.2-1
* Reference: TS 38.101-2 table 5.2-1
*
- * @return band number or {@link CellInfo@UNAVAILABLE} if not available.
+ * @return List of band number or empty list if not available.
*/
@NgranBand
- public int getBand() {
- return mBand;
+ @NonNull
+ public List<Integer> getBands() {
+ return Collections.unmodifiableList(mBands);
}
/**
@@ -205,7 +207,7 @@ public final class CellIdentityNr extends CellIdentity {
*/
@NonNull
public List<String> getAdditionalPlmns() {
- return mAdditionalPlmns;
+ return Collections.unmodifiableList(mAdditionalPlmns);
}
@Override
@@ -214,7 +216,7 @@ public final class CellIdentityNr extends CellIdentity {
.append(" mPci = ").append(mPci)
.append(" mTac = ").append(mTac)
.append(" mNrArfcn = ").append(mNrArfcn)
- .append(" mBand = ").append(mBand)
+ .append(" mBands = ").append(mBands)
.append(" mMcc = ").append(mMccStr)
.append(" mMnc = ").append(mMncStr)
.append(" mNci = ").append(mNci)
@@ -231,7 +233,7 @@ public final class CellIdentityNr extends CellIdentity {
dest.writeInt(mPci);
dest.writeInt(mTac);
dest.writeInt(mNrArfcn);
- dest.writeInt(mBand);
+ dest.writeList(mBands);
dest.writeLong(mNci);
dest.writeList(mAdditionalPlmns);
}
@@ -242,7 +244,7 @@ public final class CellIdentityNr extends CellIdentity {
mPci = in.readInt();
mTac = in.readInt();
mNrArfcn = in.readInt();
- mBand = in.readInt();
+ mBands = in.readArrayList(null);
mNci = in.readLong();
mAdditionalPlmns = in.readArrayList(null);
}
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index aebe78031ba2..1ba21f29df11 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -17,7 +17,6 @@
package android.telephony;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -60,7 +59,7 @@ public final class ModemActivityInfo implements Parcelable {
private int mRxTimeMs;
public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
- @Nullable int[] txTimeMs, int rxTimeMs) {
+ @NonNull int[] txTimeMs, int rxTimeMs) {
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
@@ -69,13 +68,10 @@ public final class ModemActivityInfo implements Parcelable {
}
/** helper API to populate tx power range for each bucket **/
- private void populateTransmitPowerRange(@Nullable int[] transmitPowerMs) {
+ private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
int i = 0;
- if (transmitPowerMs != null) {
- for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
- mTransmitPowerInfo.add(i,
- new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
- }
+ for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
+ mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
}
// Make sure that mTransmitPowerInfo is fully initialized.
for ( ; i < TX_POWER_LEVELS; i++) {
@@ -98,7 +94,7 @@ public final class ModemActivityInfo implements Parcelable {
return 0;
}
- public static final @NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
new Parcelable.Creator<ModemActivityInfo>() {
public ModemActivityInfo createFromParcel(Parcel in) {
long timestamp = in.readLong();
@@ -153,7 +149,7 @@ public final class ModemActivityInfo implements Parcelable {
}
/** @hide */
- public void setTransmitTimeMillis(@Nullable int[] txTimeMs) {
+ public void setTransmitTimeMillis(int[] txTimeMs) {
populateTransmitPowerRange(txTimeMs);
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 63a85fa2845c..247ffd7313b9 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -54,6 +54,7 @@ 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;
@@ -677,6 +678,13 @@ public class SubscriptionManager {
public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
+ * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+ * subscription.
+ * @hide
+ */
+ public static final String IMS_RCS_UCE_ENABLED = SimInfo.IMS_RCS_UCE_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.
@@ -976,10 +984,7 @@ public class SubscriptionManager {
private INetworkPolicyManager getINetworkPolicyManager() {
if (mNetworkPolicy == null) {
mNetworkPolicy = INetworkPolicyManager.Stub.asInterface(
- TelephonyFrameworkInitializer
- .getTelephonyServiceManager()
- .getNetworkPolicyServiceRegisterer()
- .get());
+ ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
}
return mNetworkPolicy;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a1f3cefb59b7..1d89665c1670 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -99,7 +99,6 @@ import com.android.internal.telephony.IOns;
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.IUpdateAvailableNetworksCallback;
import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
@@ -2781,7 +2780,7 @@ public class TelephonyManager {
@UnsupportedAppUsage
public boolean isNetworkRoaming(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
- return getTelephonyProperty(subId, TelephonyProperties.operator_is_roaming(), false);
+ return getTelephonyProperty(phoneId, TelephonyProperties.operator_is_roaming(), false);
}
/**
@@ -5624,14 +5623,6 @@ public class TelephonyManager {
.getTelephonyServiceManager().getTelephonyServiceRegisterer().get());
}
- private ITelephonyRegistry getTelephonyRegistry() {
- return ITelephonyRegistry.Stub.asInterface(
- TelephonyFrameworkInitializer
- .getTelephonyServiceManager()
- .getTelephonyRegistryServiceRegisterer()
- .get());
- }
-
private IOns getIOns() {
return IOns.Stub.asInterface(
TelephonyFrameworkInitializer
@@ -5685,29 +5676,27 @@ public class TelephonyManager {
*/
public void listen(PhoneStateListener listener, int events) {
if (mContext == null) return;
- try {
- boolean notifyNow = (getITelephony() != null);
- ITelephonyRegistry registry = getTelephonyRegistry();
- if (registry != null) {
- // subId from PhoneStateListener is deprecated Q on forward, use the subId from
- // TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q.
- int subId = mSubId;
- if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
- // since mSubId in PhoneStateListener is deprecated from Q on forward, this is
- // the only place to set mSubId and its for "informational" only.
- // TODO: remove this once we completely get rid of mSubId in PhoneStateListener
- listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
- ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
- } else if (listener.mSubId != null) {
- subId = listener.mSubId;
- }
- registry.listenForSubscriber(subId, getOpPackageName(), getFeatureId(),
- listener.callback, events, notifyNow);
- } else {
- Rlog.w(TAG, "telephony registry not ready.");
- }
- } catch (RemoteException ex) {
- // system process dead
+ boolean notifyNow = (getITelephony() != null);
+ TelephonyRegistryManager telephonyRegistry =
+ (TelephonyRegistryManager)
+ mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+ if (telephonyRegistry != null) {
+ // subId from PhoneStateListener is deprecated Q on forward, use the subId from
+ // TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q.
+ int subId = mSubId;
+ if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
+ // since mSubId in PhoneStateListener is deprecated from Q on forward, this is
+ // the only place to set mSubId and its for "informational" only.
+ // TODO: remove this once we completely get rid of mSubId in PhoneStateListener
+ listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
+ ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
+ } else if (listener.mSubId != null) {
+ subId = listener.mSubId;
+ }
+ telephonyRegistry.listenForSubscriber(subId, getOpPackageName(), getFeatureId(),
+ listener, events, notifyNow);
+ } else {
+ Rlog.w(TAG, "telephony registry not ready.");
}
}
@@ -8095,6 +8084,30 @@ public class TelephonyManager {
}
/**
+ * Get the PLMN chosen for Manual Network Selection if active.
+ * Return empty string if in automatic selection.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges})
+ *
+ * @return manually selected network info on success or empty string on failure
+ */
+ @SuppressAutoDoc // No support carrier privileges (b/72967236).
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public @NonNull String getManualNetworkSelectionPlmn() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null && isManualNetworkSelectionAllowed()) {
+ return telephony.getManualNetworkSelectionPlmn(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getManualNetworkSelectionPlmn RemoteException", ex);
+ }
+ return "";
+ }
+
+ /**
* Query Telephony to see if there has recently been an emergency SMS sent to the network by the
* user and we are still within the time interval after the emergency SMS was sent that we are
* considered in Emergency SMS mode.
@@ -11147,15 +11160,18 @@ public class TelephonyManager {
/**
* Checks if manual network selection is allowed.
*
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges})
+ *
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @return {@code true} if manual network selection is allowed, otherwise return {@code false}.
- *
- * @hide
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRECISE_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public boolean isManualNetworkSelectionAllowed() {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index d5a48df149f1..7488a1aec0e5 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -38,6 +38,9 @@ import com.android.internal.telephony.euicc.IEuiccController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
@@ -246,13 +249,69 @@ public class EuiccManager {
* Key for an extra set on {@link PendingIntent} result callbacks providing a detailed result
* code.
*
- * <p>This code is an implementation detail of the embedded subscription manager and is only
- * intended for logging or debugging purposes.
+ * <p>The value of this key is an integer and contains two portions. The first byte is
+ * OperationCode and the reaming three bytes is the ErrorCode.
+ *
+ * OperationCode is the first byte of the result code and is a categorization which defines what
+ * type of operation took place when an error occurred. e.g {@link #OPERATION_DOWNLOAD} means
+ * the error is related to download.Since the OperationCode only uses at most one byte, the
+ * maximum allowed quantity is 255(0xFF).
+ *
+ * ErrorCode is the remaining three bytes of the result code, and it denotes what happened.
+ * e.g a combination of {@link #OPERATION_DOWNLOAD} and {@link #ERROR_TIME_OUT} will suggest the
+ * download operation has timed out. The only exception here is
+ * {@link #OPERATION_SMDX_SUBJECT_REASON_CODE}, where instead of ErrorCode, SubjectCode[5.2.6.1
+ * from GSMA (SGP.22 v2.2) and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) are encoded. @see
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE} and
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE}
+ *
+ * In the case where ErrorCode contains a value of 0, it means it's an unknown error. E.g Intent
+ * only contains {@link #OPERATION_DOWNLOAD} and ErrorCode is 0 implies this is an unknown
+ * Download error.
+ *
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE}
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE}
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE}
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE}
*/
public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE =
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
/**
+ * Key for an extra set on {@link PendingIntent} result callbacks providing a
+ * OperationCode of {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE},
+ * value will be an int.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_OPERATION_CODE";
+
+ /**
+ * Key for an extra set on {@link PendingIntent} result callbacks providing a
+ * ErrorCode of {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE},
+ * value will be an int.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_ERROR_CODE";
+
+ /**
+ * Key for an extra set on {@link PendingIntent} result callbacks providing a
+ * SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2) decoded from
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}.
+ * The value of this extra will be a String.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE";
+
+ /**
+ * Key for an extra set on {@link PendingIntent} result callbacks providing a
+ * ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) decoded from
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}.
+ * The value of this extra will be a String.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE";
+
+ /**
* Key for an extra set on {@code #getDownloadableSubscriptionMetadata} PendingIntent result
* callbacks providing the downloadable subscription metadata.
*/
@@ -491,6 +550,259 @@ public class EuiccManager {
@SystemApi
public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
+ /**
+ * List of OperationCode corresponding to {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}'s
+ * value, an integer. @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"OPERATION_"}, value = {
+ OPERATION_SYSTEM,
+ OPERATION_SIM_SLOT,
+ OPERATION_EUICC_CARD,
+ OPERATION_SWITCH,
+ OPERATION_DOWNLOAD,
+ OPERATION_METADATA,
+ OPERATION_EUICC_GSMA,
+ OPERATION_APDU,
+ OPERATION_SMDX,
+ OPERATION_HTTP,
+ OPERATION_SMDX_SUBJECT_REASON_CODE,
+ })
+ public @interface OperationCode {
+ }
+
+ /**
+ * Internal system error.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_SYSTEM = 1;
+
+ /**
+ * SIM slot error. Failed to switch slot, failed to access the physical slot etc.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_SIM_SLOT = 2;
+
+ /**
+ * eUICC card error.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_EUICC_CARD = 3;
+
+ /**
+ * Generic switching profile error
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_SWITCH = 4;
+
+ /**
+ * Download profile error.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_DOWNLOAD = 5;
+
+ /**
+ * Subscription's metadata error
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_METADATA = 6;
+
+ /**
+ * eUICC returned an error defined in GSMA (SGP.22 v2.2) while running one of the ES10x
+ * functions.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_EUICC_GSMA = 7;
+
+ /**
+ * The exception of failing to execute an APDU command. It can be caused by an error
+ * happening on opening the basic or logical channel, or the response of the APDU command is
+ * not success (0x9000).
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_APDU = 8;
+
+ /**
+ * SMDX(SMDP/SMDS) error
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_SMDX = 9;
+
+ /**
+ * SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] error from GSMA (SGP.22 v2.2)
+ * When {@link #OPERATION_SMDX_SUBJECT_REASON_CODE} is used as the
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}, the remaining three bytes of the integer
+ * result from {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} will be used to stored the
+ * SubjectCode and ReasonCode from the GSMA spec and NOT ErrorCode.
+ *
+ * The encoding will follow the format of:
+ * 1. The first byte of the result will be 255(0xFF).
+ * 2. Remaining three bytes(24 bits) will be split into six sections, 4 bits in each section.
+ * 3. A SubjectCode/ReasonCode will take 12 bits each.
+ * 4. The maximum number can be represented per section is 15, as that is the maximum number
+ * allowed to be stored into 4 bits
+ * 5. Maximum supported nested category from GSMA is three layers. E.g 8.11.1.2 is not
+ * supported.
+ *
+ * E.g given SubjectCode(8.11.1) and ReasonCode(5.1)
+ *
+ * Base10: 0 10 8 11 1 0 5 1
+ * Base2: 0000 1010 1000 1011 0001 0000 0101 0001
+ * Base16: 0 A 8 B 1 0 5 1
+ *
+ * Thus the integer stored in {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} is
+ * 0xA8B1051(176885841)
+ *
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_SMDX_SUBJECT_REASON_CODE = 10;
+
+ /**
+ * HTTP error
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int OPERATION_HTTP = 11;
+
+ /**
+ * List of ErrorCode corresponding to {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_CARRIER_LOCKED,
+ ERROR_INVALID_ACTIVATION_CODE,
+ ERROR_INVALID_CONFIRMATION_CODE,
+ ERROR_INCOMPATIBLE_CARRIER,
+ ERROR_EUICC_INSUFFICIENT_MEMORY,
+ ERROR_TIME_OUT,
+ ERROR_EUICC_MISSING,
+ ERROR_UNSUPPORTED_VERSION,
+ ERROR_SIM_MISSING,
+ ERROR_INSTALL_PROFILE,
+ ERROR_DISALLOWED_BY_PPR,
+ ERROR_ADDRESS_MISSING,
+ ERROR_CERTIFICATE_ERROR,
+ ERROR_NO_PROFILES_AVAILABLE,
+ ERROR_CONNECTION_ERROR,
+ ERROR_INVALID_RESPONSE,
+ ERROR_OPERATION_BUSY,
+ })
+ public @interface ErrorCode{}
+
+ /**
+ * Operation such as downloading/switching to another profile failed due to device being
+ * carrier locked.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_CARRIER_LOCKED = 10000;
+
+ /**
+ * The activation code(SGP.22 v2.2 section[4.1]) is invalid.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_INVALID_ACTIVATION_CODE = 10001;
+
+ /**
+ * The confirmation code(SGP.22 v2.2 section[4.7]) is invalid.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_INVALID_CONFIRMATION_CODE = 10002;
+
+ /**
+ * The profile's carrier is incompatible with the LPA.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_INCOMPATIBLE_CARRIER = 10003;
+
+ /**
+ * There is no more space available on the eUICC for new profiles.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_EUICC_INSUFFICIENT_MEMORY = 10004;
+
+ /**
+ * Timed out while waiting for an operation to complete. i.e restart, disable,
+ * switch reset etc.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_TIME_OUT = 10005;
+
+ /**
+ * eUICC is missing or defective on the device.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_EUICC_MISSING = 10006;
+
+ /**
+ * The eUICC card(hardware) version is incompatible with the software
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_UNSUPPORTED_VERSION = 10007;
+
+ /**
+ * No SIM card is available in the device.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_SIM_MISSING = 10008;
+
+ /**
+ * Failure to load the profile onto the eUICC card. e.g
+ * 1. iccid of the profile already exists on the eUICC.
+ * 2. GSMA(.22 v2.2) Profile Install Result - installFailedDueToDataMismatch
+ * 3. operation was interrupted
+ * 4. SIMalliance error in PEStatus(SGP.22 v2.2 section 2.5.6.1)
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_INSTALL_PROFILE = 10009;
+
+ /**
+ * Failed to load profile onto eUICC due to Profile Poicly Rules.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_DISALLOWED_BY_PPR = 10010;
+
+
+ /**
+ * Address is missing e.g SMDS/SMDP address is missing.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_ADDRESS_MISSING = 10011;
+
+ /**
+ * Certificate needed for authentication is not valid or missing. E.g SMDP/SMDS authentication
+ * failed.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_CERTIFICATE_ERROR = 10012;
+
+
+ /**
+ * No profiles available.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_NO_PROFILES_AVAILABLE = 10013;
+
+ /**
+ * Failure to create a connection.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_CONNECTION_ERROR = 10014;
+
+ /**
+ * Response format is invalid. e.g SMDP/SMDS response contains invalid json, header or/and ASN1.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_INVALID_RESPONSE = 10015;
+
+ /**
+ * The operation is currently busy, try again later.
+ * @see {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} for details
+ */
+ public static final int ERROR_OPERATION_BUSY = 10016;
+
private final Context mContext;
private int mCardId;
@@ -939,6 +1251,138 @@ public class EuiccManager {
}
/**
+ * Sets the supported countries for eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * <p>The supported country list will be replaced by {@code supportedCountries}. For how we
+ * determine whether a country is supported please check {@link #isSupportedCountry}.
+ *
+ * @param supportedCountries is a list of strings contains country ISO codes in uppercase.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ public void setSupportedCountries(@NonNull List<String> supportedCountries) {
+ if (!isEnabled()) {
+ return;
+ }
+ try {
+ getIEuiccController().setSupportedCountries(
+ true /* isSupported */,
+ supportedCountries.stream()
+ .map(String::toUpperCase).collect(Collectors.toList()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the unsupported countries for eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * <p>The unsupported country list will be replaced by {@code unsupportedCountries}. For how we
+ * determine whether a country is supported please check {@link #isSupportedCountry}.
+ *
+ * @param unsupportedCountries is a list of strings contains country ISO codes in uppercase.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ public void setUnsupportedCountries(@NonNull List<String> unsupportedCountries) {
+ if (!isEnabled()) {
+ return;
+ }
+ try {
+ getIEuiccController().setSupportedCountries(
+ false /* isSupported */,
+ unsupportedCountries.stream()
+ .map(String::toUpperCase).collect(Collectors.toList()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the supported countries for eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * @return list of strings contains country ISO codes in uppercase.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ @NonNull
+ public List<String> getSupportedCountries() {
+ if (!isEnabled()) {
+ return Collections.emptyList();
+ }
+ try {
+ return getIEuiccController().getSupportedCountries(true /* isSupported */);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the unsupported countries for eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * @return list of strings contains country ISO codes in uppercase.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ @NonNull
+ public List<String> getUnsupportedCountries() {
+ if (!isEnabled()) {
+ return Collections.emptyList();
+ }
+ try {
+ return getIEuiccController().getSupportedCountries(false /* isSupported */);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether the given country supports eUICC.
+ *
+ * <p>Supported country list has a higher prority than unsupported country list. If the
+ * supported country list is not empty, {@code countryIso} will be considered as supported when
+ * it exists in the supported country list. Otherwise {@code countryIso} is not supported. If
+ * the supported country list is empty, {@code countryIso} will be considered as supported if it
+ * does not exist in the unsupported country list. Otherwise {@code countryIso} is not
+ * supported. If both supported and unsupported country lists are empty, then all countries are
+ * consider be supported. For how to set supported and unsupported country list, please check
+ * {@link #setSupportedCountries} and {@link #setUnsupportedCountries}.
+ *
+ * @param countryIso should be the ISO-3166 country code is provided in uppercase 2 character
+ * format.
+ * @return whether the given country supports eUICC or not.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ public boolean isSupportedCountry(@NonNull String countryIso) {
+ if (!isEnabled()) {
+ return false;
+ }
+ try {
+ return getIEuiccController().isSupportedCountry(countryIso.toUpperCase());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Refreshes the cardId if its uninitialized, and returns whether we should continue the
* operation.
* <p>
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 8c9765b4bf70..9c1be48e247a 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -328,6 +328,14 @@ public final class ImsCallProfile implements Parcelable {
@Deprecated
public static final String EXTRA_CALL_RAT_TYPE_ALT = "callRadioTech";
+ /**
+ * String extra property containing forwarded numbers associated with the current connection
+ * for an IMS call. The value is string array, and it can include multiple numbers, and
+ * the array values are expected E164 (e.g. +1 (650) 253-0000) format.
+ */
+ public static final String EXTRA_FORWARDED_NUMBER =
+ "android.telephony.ims.extra.FORWARDED_NUMBER";
+
/** @hide */
public int mServiceType;
/** @hide */
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 2e3f59a13670..72167761c88d 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,6 +21,8 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -28,6 +30,7 @@ import android.os.RemoteException;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -41,6 +44,8 @@ import java.util.concurrent.Executor;
* @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
* @hide
*/
+@SystemApi
+@TestApi
public class RcsUceAdapter {
private static final String TAG = "RcsUceAdapter";
@@ -169,6 +174,7 @@ public class RcsUceAdapter {
* Provides a one-time callback for the response to a UCE request. After this callback is called
* by the framework, the reference to this callback will be discarded on the service side.
* @see #requestCapabilities(Executor, List, CapabilitiesCallback)
+ * @hide
*/
public static class CapabilitiesCallback {
@@ -196,6 +202,7 @@ public class RcsUceAdapter {
/**
* Not to be instantiated directly, use
* {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+ * @hide
*/
RcsUceAdapter(int subId) {
mSubId = subId;
@@ -219,6 +226,7 @@ public class RcsUceAdapter {
* {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
* available. This can happen if the ImsService has crashed, for example, or if the subscription
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ * @hide
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void requestCapabilities(@CallbackExecutor Executor executor,
@@ -281,6 +289,7 @@ public class RcsUceAdapter {
* {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
* available. This can happen if the ImsService has crashed, for example, or if the subscription
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+ * @hide
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @PublishState int getUcePublishState() throws ImsException {
@@ -305,7 +314,7 @@ public class RcsUceAdapter {
* for the associated subscription.
*
* @return true if the user’s setting for UCE is enabled, false otherwise. If false,
- * {@link ImsRcsManager#isCapable(int)} will return false for
+ * {@link ImsRcsManager#isCapable(int, int)} will return false for
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE}
* @see #setUceSettingEnabled(boolean)
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 3ec4f3468497..f13371c1d0fa 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -17,6 +17,8 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -206,6 +208,13 @@ public class ImsUtImplBase {
return ImsUtImplBase.this.updateCallBarringForServiceClass(
cbType, action, barrList, serviceClass);
}
+
+ @Override
+ public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
+ int serviceClass, String password) throws RemoteException {
+ return ImsUtImplBase.this.updateCallBarringWithPassword(
+ cbType, action, barrList, serviceClass, password);
+ }
};
/**
@@ -328,6 +337,14 @@ public class ImsUtImplBase {
}
/**
+ * Updates the configuration of the call barring for specified service class with password.
+ */
+ public int updateCallBarringWithPassword(int cbType, int action, @Nullable String[] barrList,
+ int serviceClass, @NonNull String password) {
+ return -1;
+ }
+
+ /**
* Updates the configuration of the call forward.
*/
public int updateCallForward(int action, int condition, String number, int serviceClass,
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 15f837189843..4a5380e4551b 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -166,6 +166,12 @@ public interface ImsUtInterface {
String[] barrList, int serviceClass);
/**
+ * Modifies the configuration of the call barring for specified service class with password.
+ */
+ public void updateCallBarring(int cbType, int action, Message result,
+ String[] barrList, int serviceClass, String password);
+
+ /**
* Modifies the configuration of the call forward.
*/
public void updateCallForward(int action, int condition, String number,
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4f97cc5cfb22..302be65070f7 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -122,4 +122,10 @@ interface IImsUt {
*/
int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
int serviceClass);
+
+ /**
+ * Updates the configuration of the call barring for specified service class with password.
+ */
+ int updateCallBarringWithPassword(int cbType, int action, in String[] barrList,
+ int serviceClass, String password);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0bc6640a8331..6aa5a52d55d5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2197,4 +2197,13 @@ interface ITelephony {
* This is safe to call from any thread, with any window manager locks held or not.
*/
oneway void userActivity();
+
+ /**
+ * Get the user manual network selection.
+ * Return empty string if in automatic selection.
+ *
+ * @param subId the id of the subscription
+ * @return operatorinfo on success
+ */
+ String getManualNetworkSelectionPlmn(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 0db86d6054b3..9ac8cb136c6b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -480,6 +480,7 @@ public interface RILConstants {
int RIL_REQUEST_STOP_KEEPALIVE = 145;
int RIL_REQUEST_ENABLE_MODEM = 146;
int RIL_REQUEST_GET_MODEM_STATUS = 147;
+ int RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE = 148;
/* The following requests are not defined in RIL.h */
int RIL_REQUEST_HAL_NON_RIL_BASE = 200;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index b697d5835b09..48f785091764 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -212,37 +212,6 @@ public class TelephonyIntents {
public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
/**
- * Broadcast Action: The Service Provider string(s) have been updated. Activities or
- * services that use these strings should update their display.
- * The intent will have the following extra values:</p>
- *
- * <dl>
- * <dt>showPlmn</dt><dd>Boolean that indicates whether the PLMN should be shown.</dd>
- * <dt>plmn</dt><dd>The operator name of the registered network, as a string.</dd>
- * <dt>showSpn</dt><dd>Boolean that indicates whether the SPN should be shown.</dd>
- * <dt>spn</dt><dd>The service provider name, as a string.</dd>
- * </dl>
- *
- * Note that <em>showPlmn</em> may indicate that <em>plmn</em> should be displayed, even
- * though the value for <em>plmn</em> is null. This can happen, for example, if the phone
- * has not registered to a network yet. In this case the receiver may substitute an
- * appropriate placeholder string (eg, "No service").
- *
- * It is recommended to display <em>plmn</em> before / above <em>spn</em> if
- * both are displayed.
- *
- * <p>Note: this is a protected intent that can only be sent by the system.
- */
- public static final String SPN_STRINGS_UPDATED_ACTION =
- "android.provider.Telephony.SPN_STRINGS_UPDATED";
-
- public static final String EXTRA_SHOW_PLMN = "showPlmn";
- public static final String EXTRA_PLMN = "plmn";
- public static final String EXTRA_SHOW_SPN = "showSpn";
- public static final String EXTRA_SPN = "spn";
- public static final String EXTRA_DATA_SPN = "spnData";
-
- /**
* <p>Broadcast Action: It indicates one column of a subinfo record has been changed
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 7422863d862c..35e8a12e898a 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
+import java.util.List;
/** @hide */
interface IEuiccController {
@@ -47,4 +48,7 @@ interface IEuiccController {
oneway void eraseSubscriptionsWithOptions(
int cardId, int options, in PendingIntent callbackIntent);
oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+ void setSupportedCountries(boolean isSupported, in List<String> countriesList);
+ List<String> getSupportedCountries(boolean isSupported);
+ boolean isSupportedCountry(String countryIso);
}
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index cc260ac14147..32ca250b6c74 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -2,7 +2,6 @@
package android.test.mock {
public class MockContext extends android.content.Context {
- method public android.view.Display getDisplay();
method public int getDisplayId();
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 9d913b9861e5..36074edd187e 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -17,6 +17,7 @@
package android.test.mock;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -811,6 +812,11 @@ public class MockContext extends Context {
}
@Override
+ public @NonNull Context createWindowContext(int type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isRestricted() {
throw new UnsupportedOperationException();
}
@@ -821,7 +827,6 @@ public class MockContext extends Context {
throw new UnsupportedOperationException();
}
- /** @hide */
@Override
public Display getDisplay() {
throw new UnsupportedOperationException();
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index e7a63e414172..78850c534596 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -30,7 +30,23 @@ cc_test {
"-g",
],
shared_libs: ["libbase", "libutils"],
+ // For some reasons, cuttlefish (x86) uses x86_64 test suites for testing. Unfortunately, when
+ // the uploader does not pick up the executable from correct output location. The following
+ // workaround allows the test to:
+ // * upload the 32-bit exectuable for both 32 and 64 bits devices to use
+ // * refer to the same executable name in Java
+ // * no need to force the Java test to be archiecture specific.
+ //
+ // See b/145573317 for details.
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ lib64: {
+ suffix: "64", // not really used
+ },
+ },
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "pts"],
gtest: false,
}
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
index 65a3d8a337db..c900eaedbdae 100644
--- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
+++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java
@@ -30,6 +30,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import java.util.Arrays;
+import java.util.Locale;
import java.util.Random;
import java.util.UUID;
@@ -38,7 +39,8 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@SmallTest
public void testKeyphraseParcelUnparcel_noUsers() throws Exception {
- Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", null);
+ Keyphrase keyphrase = new Keyphrase(1, 0,
+ Locale.forLanguageTag("en-US"), "hello", null);
// Write to a parcel
Parcel parcel = Parcel.obtain();
@@ -57,7 +59,8 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@SmallTest
public void testKeyphraseParcelUnparcel_zeroUsers() throws Exception {
- Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[0]);
+ Keyphrase keyphrase = new Keyphrase(1, 0,
+ Locale.forLanguageTag("en-US"), "hello", new int[0]);
// Write to a parcel
Parcel parcel = Parcel.obtain();
@@ -76,7 +79,8 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@SmallTest
public void testKeyphraseParcelUnparcel_pos() throws Exception {
- Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[] {1, 2, 3, 4, 5});
+ Keyphrase keyphrase = new Keyphrase(1, 0,
+ Locale.forLanguageTag("en-US"), "hello", new int[] {1, 2, 3, 4, 5});
// Write to a parcel
Parcel parcel = Parcel.obtain();
@@ -96,8 +100,10 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@SmallTest
public void testKeyphraseSoundModelParcelUnparcel_noData() throws Exception {
Keyphrase[] keyphrases = new Keyphrase[2];
- keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
- keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+ keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
+ "hello", new int[] {0});
+ keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
+ "there", new int[] {1, 2});
KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
null, keyphrases);
@@ -119,8 +125,10 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@SmallTest
public void testKeyphraseSoundModelParcelUnparcel_zeroData() throws Exception {
Keyphrase[] keyphrases = new Keyphrase[2];
- keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
- keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+ keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
+ "hello", new int[] {0});
+ keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
+ "there", new int[] {1, 2});
KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
new byte[0], keyphrases);
@@ -186,8 +194,10 @@ public class SoundTriggerTest extends InstrumentationTestCase {
@LargeTest
public void testKeyphraseSoundModelParcelUnparcel_largeData() throws Exception {
Keyphrase[] keyphrases = new Keyphrase[2];
- keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0});
- keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2});
+ keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
+ "hello", new int[] {0});
+ keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
+ "there", new int[] {1, 2});
byte[] data = new byte[200 * 1024];
mRandom.nextBytes(data);
KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
index 6687f83ad0db..61696718c76e 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
@@ -46,15 +46,15 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
mView.setZOrderOnTop(true);
mView.getHolder().addCallback(this);
+
+ addEmbeddedView();
}
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
+ void addEmbeddedView() {
mVr = new SurfaceControlViewHost(this, this.getDisplay(),
- mView.getInputToken());
+ mView.getHostToken());
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.reparent(mVr.getSurfacePackage().getSurfaceControl(), mView.getSurfaceControl()).apply();
+ mView.setChildSurfacePackage(mVr.getSurfacePackage());
Button v = new Button(this);
v.setBackgroundColor(Color.BLUE);
@@ -70,6 +70,10 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
}
@Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GREEN);
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index 54c944f9588e..b357ad076c11 100644
--- a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -16,9 +16,6 @@
package com.android.test.voiceenrollment;
-import java.util.Random;
-import java.util.UUID;
-
import android.app.Activity;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
@@ -29,6 +26,13 @@ import android.util.Log;
import android.view.View;
import android.widget.Toast;
+import java.util.Locale;
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * TODO: must be transitioned to a service.
+ */
public class TestEnrollmentActivity extends Activity {
private static final String TAG = "TestEnrollmentActivity";
private static final boolean DBG = false;
@@ -56,7 +60,8 @@ public class TestEnrollmentActivity extends Activity {
* Performs a fresh enrollment.
*/
public void onEnrollButtonClicked(View v) {
- Keyphrase kp = new Keyphrase(KEYPHRASE_ID, RECOGNITION_MODES, BCP47_LOCALE, TEXT,
+ Keyphrase kp = new Keyphrase(KEYPHRASE_ID, RECOGNITION_MODES,
+ Locale.forLanguageTag(BCP47_LOCALE), TEXT,
new int[] { UserManager.get(this).getUserHandle() /* current user */});
UUID modelUuid = UUID.randomUUID();
// Generate a fake model to push.
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
index f3c89d8addf6..01e212d01574 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -22,6 +22,7 @@ import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.Insets;
import android.os.Bundle;
+import android.util.Log;
import android.util.Property;
import android.view.View;
import android.view.WindowInsets;
@@ -67,8 +68,8 @@ public class WindowInsetsActivity extends Activity {
}
};
- float showY;
- float hideY;
+ float startY;
+ float endY;
InsetsAnimation imeAnim;
@Override
@@ -84,16 +85,6 @@ public class WindowInsetsActivity extends Activity {
v.getWindowInsetsController().hide(Type.ime());
}
});
- mRoot.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
- if (imeAnim == null) {
- return;
- }
- if (mRoot.getRootWindowInsets().isVisible(Type.ime())) {
- showY = mButton.getTop();
- } else {
- hideY = mButton.getTop();
- }
- });
mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimationCallback() {
@Override
@@ -106,22 +97,19 @@ public class WindowInsetsActivity extends Activity {
if ((animation.getTypeMask() & Type.ime()) != 0) {
imeAnim = animation;
}
- if (mRoot.getRootWindowInsets().isVisible(Type.ime())) {
- showY = mButton.getTop();
- } else {
- hideY = mButton.getTop();
- }
+ startY = mButton.getTop();
}
@Override
public WindowInsets onProgress(WindowInsets insets) {
- mButton.setY(hideY + (showY - hideY) * imeAnim.getInterpolatedFraction());
+ mButton.setY(startY + (endY - startY) * imeAnim.getInterpolatedFraction());
return insets;
}
@Override
public AnimationBounds onStart(InsetsAnimation animation,
AnimationBounds bounds) {
+ endY = mButton.getTop();
return bounds;
}
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index b2e573b6c74b..096f7bdca088 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -38,6 +38,8 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.SystemClock;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -316,11 +318,83 @@ public class LinkAddressTest {
l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
assertParcelingIsLossless(l);
+ l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
+ 1L, 3600000L);
+ assertParcelingIsLossless(l);
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelSane(l, 4);
+ assertParcelSane(l, 6);
}
+ @Test
+ public void testDeprecationTime() {
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ LinkAddress.LIFETIME_UNKNOWN,
+ SystemClock.elapsedRealtime() + 200000);
+ fail("Only one time provided should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ SystemClock.elapsedRealtime() - 100000,
+ SystemClock.elapsedRealtime() - 200000);
+ fail("deprecation time later than expiration time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ -2, SystemClock.elapsedRealtime());
+ fail("negative deprecation time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
+ public void testExpirationTime() {
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ SystemClock.elapsedRealtime() + 200000,
+ LinkAddress.LIFETIME_UNKNOWN);
+ fail("Only one time provided should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ SystemClock.elapsedRealtime() - 10000, -2);
+ fail("negative expiration time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
+ public void testGetFlags() {
+ LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
+ assertEquals(123, l.getFlags());
+
+ // Test if deprecated bit was added/remove automatically based on the provided deprecation
+ // time
+ l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
+ SystemClock.elapsedRealtime() - 100000, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the flag is added automatically.
+ assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+ SystemClock.elapsedRealtime() + 100000, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the flag is removed automatically.
+ assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+ LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the permanent flag is added.
+ assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
+ SystemClock.elapsedRealtime() - 100000,
+ SystemClock.elapsedRealtime() + 100000);
+ // Check if the permanent flag is removed
+ assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
+ }
+
+
private void assertGlobalPreferred(LinkAddress l, String msg) {
assertTrue(msg, l.isGlobalPreferred());
}
@@ -389,5 +463,12 @@ public class LinkAddressTest {
(IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
+ RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
+ SystemClock.elapsedRealtime() + 200000);
+ // Although the deprecated bit is set, but the deprecation time is in the future, test
+ // if the flag is removed automatically.
+ assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
}
}
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
new file mode 100644
index 000000000000..065add4fc253
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
+
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.PersistableBundle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConnectivityDiagnosticsManagerTest {
+ private static final int NET_ID = 1;
+ private static final int DETECTION_METHOD = 2;
+ private static final long TIMESTAMP = 10L;
+ private static final String INTERFACE_NAME = "interface";
+ private static final String BUNDLE_KEY = "key";
+ private static final String BUNDLE_VALUE = "value";
+
+ private ConnectivityReport createSampleConnectivityReport() {
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(INTERFACE_NAME);
+
+ final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ return new ConnectivityReport(
+ new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
+ }
+
+ private ConnectivityReport createDefaultConnectivityReport() {
+ return new ConnectivityReport(
+ new Network(0),
+ 0L,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY);
+ }
+
+ @Test
+ public void testPersistableBundleEquals() {
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ null, PersistableBundle.EMPTY));
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ PersistableBundle.EMPTY, null));
+ assertTrue(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ PersistableBundle.EMPTY, PersistableBundle.EMPTY));
+
+ final PersistableBundle a = new PersistableBundle();
+ a.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ final PersistableBundle b = new PersistableBundle();
+ b.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ final PersistableBundle c = new PersistableBundle();
+ c.putString(BUNDLE_KEY, null);
+
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
+
+ assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
+ assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
+
+ assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
+ assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
+ }
+
+ @Test
+ public void testConnectivityReportEquals() {
+ assertEquals(createSampleConnectivityReport(), createSampleConnectivityReport());
+ assertEquals(createDefaultConnectivityReport(), createDefaultConnectivityReport());
+
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(INTERFACE_NAME);
+
+ final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(NET_ID),
+ 0L,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ 0L,
+ linkProperties,
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ networkCapabilities,
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ bundle));
+ }
+
+ @Test
+ public void testConnectivityReportParcelUnparcel() {
+ assertParcelSane(createSampleConnectivityReport(), 5);
+ }
+
+ private DataStallReport createSampleDataStallReport() {
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+ return new DataStallReport(new Network(NET_ID), TIMESTAMP, DETECTION_METHOD, bundle);
+ }
+
+ private DataStallReport createDefaultDataStallReport() {
+ return new DataStallReport(new Network(0), 0L, 0, PersistableBundle.EMPTY);
+ }
+
+ @Test
+ public void testDataStallReportEquals() {
+ assertEquals(createSampleDataStallReport(), createSampleDataStallReport());
+ assertEquals(createDefaultDataStallReport(), createDefaultDataStallReport());
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(NET_ID), 0L, 0, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(0), TIMESTAMP, 0, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(0), 0L, DETECTION_METHOD, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(), new DataStallReport(new Network(0), 0L, 0, bundle));
+ }
+
+ @Test
+ public void testDataStallReportParcelUnparcel() {
+ assertParcelSane(createSampleDataStallReport(), 4);
+ }
+}
diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
index 51d74f0fcfa9..d14ec57ea07a 100644
--- a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
+++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
@@ -17,6 +17,7 @@
package android.net.wifi;
import android.net.wifi.INetworkRequestUserSelectionCallback;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
/**
@@ -30,7 +31,7 @@ oneway interface INetworkRequestMatchCallback
void onAbort();
- void onMatch(in List<android.net.wifi.ScanResult> scanResults);
+ void onMatch(in List<ScanResult> scanResults);
void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index d13a625963b6..31b3a5064932 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -36,6 +36,7 @@ import android.net.wifi.ISuggestionConnectionStatusListener;
import android.net.wifi.ITrafficStateCallback;
import android.net.wifi.ITxPacketCountListener;
import android.net.wifi.IWifiConnectedNetworkScorer;
+import android.net.wifi.ScanResult;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
@@ -60,9 +61,9 @@ interface IWifiManager
ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId);
- Map getAllMatchingFqdnsForScanResults(in List<android.net.wifi.ScanResult> scanResult);
+ Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
- Map getMatchingOsuProviders(in List<android.net.wifi.ScanResult> scanResult);
+ Map getMatchingOsuProviders(in List<ScanResult> scanResult);
Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders);
@@ -88,15 +89,19 @@ interface IWifiManager
boolean disableNetwork(int netId, String packageName);
+ void allowAutojoinGlobal(boolean choice);
+
void allowAutojoin(int netId, boolean choice);
void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable);
+ void setMeteredOverridePasspoint(String fqdn, int meteredOverride);
+
boolean startScan(String packageName, String featureId);
- List<android.net.wifi.ScanResult> getScanResults(String callingPackage, String callingFeatureId);
+ List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
boolean disconnect(String packageName);
@@ -179,8 +184,6 @@ interface IWifiManager
int getVerboseLoggingLevel();
- void enableWifiConnectivityManager(boolean enabled);
-
void disableEphemeralNetwork(String SSID, String packageName);
void factoryReset(String packageName);
@@ -255,7 +258,7 @@ interface IWifiManager
int calculateSignalLevel(int rssi);
- List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<android.net.wifi.ScanResult> scanResults);
+ List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(in List<ScanResult> scanResults);
boolean setWifiConnectedNetworkScorer(in IBinder binder, in IWifiConnectedNetworkScorer scorer);
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 5edcc2df3804..04016b606b96 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -856,11 +856,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* like /etc/ssl/certs. If configured, these certificates are added to the
* list of trusted CAs. ca_cert may also be included in that case, but it is
* not required.
- * @param path The path for CA certificate files, or null/empty string to clear.
+ * @param path The path for CA certificate files, or empty string to clear.
* @hide
*/
@SystemApi
- public void setCaPath(@Nullable String path) {
+ public void setCaPath(@NonNull String path) {
setFieldValue(CA_PATH_KEY, path);
}
@@ -881,11 +881,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
* a certificate
* </p>
- * @param alias identifies the certificate, or null/empty string to clear.
+ * @param alias identifies the certificate, or empty string to clear.
* @hide
*/
@SystemApi
- public void setClientCertificateAlias(@Nullable String alias) {
+ public void setClientCertificateAlias(@NonNull String alias) {
setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
setFieldValue(PRIVATE_KEY_ID_KEY, alias, USER_PRIVATE_KEY);
// Also, set engine parameters
@@ -1360,11 +1360,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* If this field is not specified, WAPI-CERT uses ASU ID from WAI packet
* as the certificate suite name automatically.
*
- * @param wapiCertSuite The name for WAPI certificate suite, or null/empty string to clear.
+ * @param wapiCertSuite The name for WAPI certificate suite, or empty string to clear.
* @hide
*/
@SystemApi
- public void setWapiCertSuite(@Nullable String wapiCertSuite) {
+ public void setWapiCertSuite(@NonNull String wapiCertSuite) {
setFieldValue(WAPI_CERT_SUITE_KEY, wapiCertSuite);
}
@@ -1373,7 +1373,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return the certificate suite name
* @hide
*/
- @Nullable
+ @NonNull
@SystemApi
public String getWapiCertSuite() {
return getFieldValue(WAPI_CERT_SUITE_KEY);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f6e3ff0ff02c..fb3e794d92d1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -1792,18 +1793,6 @@ public class WifiManager {
}
/**
- * Same as {@link #registerNetworkRequestMatchCallback(Executor, NetworkRequestMatchCallback)},
- * except that the callback will be executed on the application's main thread.
- * @param callback Callback for network match events to register.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback) {
- registerNetworkRequestMatchCallback(mContext.getMainExecutor(), callback);
- }
-
- /**
* Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
* Caller can unregister a previously registered callback using
* {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
@@ -2353,7 +2342,7 @@ public class WifiManager {
return (getSupportedFeatures() & feature) == feature;
}
- /**
+ /**
* @return true if this adapter supports Passpoint
* @hide
*/
@@ -2905,6 +2894,7 @@ public class WifiManager {
* [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
* rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
*/
+ @IntRange(from = 0)
public int calculateSignalLevel(int rssi) {
try {
return mService.calculateSignalLevel(rssi);
@@ -2917,6 +2907,7 @@ public class WifiManager {
* Get the system default maximum signal level.
* This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
*/
+ @IntRange(from = 0)
public int getMaxSignalLevel() {
return calculateSignalLevel(Integer.MAX_VALUE);
}
@@ -3716,18 +3707,6 @@ public class WifiManager {
}
/**
- * Same as {@link #registerSoftApCallback(Executor, SoftApCallback)},
- * except that the callback will be executed on the application's main thread.
- * @param callback Callback for soft AP events
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerSoftApCallback(@NonNull SoftApCallback callback) {
- registerSoftApCallback(mContext.getMainExecutor(), callback);
- }
-
- /**
* Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the current
* soft AP state and number of connected devices immediately after a successful call to this API
* via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state
@@ -4299,6 +4278,23 @@ public class WifiManager {
}
/**
+ * Allows the OEM to enable/disable auto-join globally.
+ *
+ * @param choice true to allow autojoin, false to disallow autojoin
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void allowAutojoinGlobal(boolean choice) {
+ try {
+ mService.allowAutojoinGlobal(choice);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
* Sets the user choice for allowing auto-join to a network.
* The updated choice will be made available through the updated config supplied by the
* CONFIGURED_NETWORKS_CHANGED broadcast.
@@ -4353,6 +4349,25 @@ public class WifiManager {
}
/**
+ * Sets the user's choice of metered override for a Passpoint profile.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
+ * {@link WifiConfiguration#METERED_OVERRIDE_METERED},
+ * {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setMeteredOverridePasspoint(@NonNull String fqdn, int meteredOverride) {
+ try {
+ mService.setMeteredOverridePasspoint(fqdn, meteredOverride);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
@@ -4925,18 +4940,6 @@ public class WifiManager {
}
/**
- * Enable/disable WifiConnectivityManager
- * @hide
- */
- public void enableWifiConnectivityManager(boolean enabled) {
- try {
- mService.enableWifiConnectivityManager(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Returns a byte stream representing the data that needs to be backed up to save the
* current Wifi state.
* This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
@@ -5144,18 +5147,6 @@ public class WifiManager {
}
/**
- * Same as {@link #registerTrafficStateCallback(Executor, TrafficStateCallback)},
- * except that the callback will be executed on the application's main thread.
- * @param callback Callback for traffic state events
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerTrafficStateCallback(@NonNull TrafficStateCallback callback) {
- registerTrafficStateCallback(mContext.getMainExecutor(), callback);
- }
-
- /**
* Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
* callbacks will be invoked periodically by platform to inform clients about the current
* traffic state. Caller can unregister a previously registered callback using
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7c335fc323f5..3a0d080594c8 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -16,6 +16,9 @@
package android.net.wifi.hotspot2;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+import static android.net.wifi.WifiConfiguration.MeteredOverride;
+
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
@@ -438,6 +441,18 @@ public final class PasspointConfiguration implements Parcelable {
private boolean mIsMacRandomizationEnabled = true;
/**
+ * Indicates if the end user has expressed an explicit opinion about the
+ * meteredness of this network, such as through the Settings app.
+ * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
+ * or {@link #METERED_OVERRIDE_NOT_METERED}.
+ * <p>
+ * This should always override any values from {@link WifiInfo#getMeteredHint()}.
+ *
+ * By default this field is set to {@link #METERED_OVERRIDE_NONE}.
+ */
+ private int mMeteredOverride = METERED_OVERRIDE_NONE;
+
+ /**
* 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
@@ -463,6 +478,16 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * Sets the metered override setting for this Passpoint configuration.
+ *
+ * @param meteredOverride One of the values in {@link MeteredOverride}
+ * @hide
+ */
+ public void setMeteredOverride(@MeteredOverride int meteredOverride) {
+ mMeteredOverride = meteredOverride;
+ }
+
+ /**
* 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
@@ -478,6 +503,18 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * Indicates whether the user chose this configuration to be treated as metered or not.
+ *
+ * @return One of the values in {@link MeteredOverride}
+ * @hide
+ */
+ @SystemApi
+ @MeteredOverride
+ public int getMeteredOverride() {
+ return mMeteredOverride;
+ }
+
+ /**
* Indicates whether a randomized MAC address or device MAC address will be used for
* connections to this Passpoint network. If true, a randomized MAC address will be used.
* Otherwise, the device MAC address will be used.
@@ -534,6 +571,7 @@ public final class PasspointConfiguration implements Parcelable {
mCarrierId = source.mCarrierId;
mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
+ mMeteredOverride = source.mMeteredOverride;
}
@Override
@@ -565,6 +603,7 @@ public final class PasspointConfiguration implements Parcelable {
dest.writeInt(mCarrierId);
dest.writeBoolean(mIsAutoJoinEnabled);
dest.writeBoolean(mIsMacRandomizationEnabled);
+ dest.writeInt(mMeteredOverride);
}
@Override
@@ -597,6 +636,7 @@ public final class PasspointConfiguration implements Parcelable {
&& mCarrierId == that.mCarrierId
&& mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
&& mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
+ && mMeteredOverride == that.mMeteredOverride
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -607,7 +647,8 @@ public final class PasspointConfiguration implements Parcelable {
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled, mIsMacRandomizationEnabled);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled, mIsMacRandomizationEnabled,
+ mMeteredOverride);
}
@Override
@@ -663,6 +704,7 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("CarrierId:" + mCarrierId);
builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
+ builder.append("mMeteredOverride:" + mMeteredOverride);
return builder.toString();
}
@@ -770,6 +812,7 @@ public final class PasspointConfiguration implements Parcelable {
config.mCarrierId = in.readInt();
config.mIsAutoJoinEnabled = in.readBoolean();
config.mIsMacRandomizationEnabled = in.readBoolean();
+ config.mMeteredOverride = in.readInt();
return config;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 8fa9c3d6f1a6..9562f95ac162 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -66,12 +66,20 @@ public class WifiP2pConfig implements Parcelable {
/** @hide */
public String passphrase = "";
- /** Get the required band for the group owner. */
+ /**
+ * Get the required band for the group owner.
+ * The result will be one of the following:
+ * {@link #GROUP_OWNER_BAND_AUTO},
+ * {@link #GROUP_OWNER_BAND_2GHZ},
+ * {@link #GROUP_OWNER_BAND_5GHZ}
+ */
+ @GroupOperatingBandType
public int getGroupOwnerBand() {
return groupOwnerBand;
}
/** @hide */
+ @GroupOperatingBandType
public int groupOwnerBand = GROUP_OWNER_BAND_AUTO;
/** @hide */
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 19d09d1f2a9c..b46755349ad7 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -178,6 +178,11 @@ public class BaseWifiService extends IWifiManager.Stub {
}
@Override
+ public void allowAutojoinGlobal(boolean choice) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void allowAutojoin(int netId, boolean choice) {
throw new UnsupportedOperationException();
}
@@ -193,6 +198,11 @@ public class BaseWifiService extends IWifiManager.Stub {
}
@Override
+ public void setMeteredOverridePasspoint(String fqdn, int meteredOverride) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
@@ -404,7 +414,8 @@ public class BaseWifiService extends IWifiManager.Stub {
throw new UnsupportedOperationException();
}
- @Override
+ /** @deprecated use {@link #allowAutojoinGlobal(boolean)} instead */
+ @Deprecated
public void enableWifiConnectivityManager(boolean enabled) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f369203e05ab..0c2876e340c1 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
import static android.net.wifi.WifiManager.ActionListener;
import static android.net.wifi.WifiManager.BUSY;
import static android.net.wifi.WifiManager.ERROR;
@@ -881,17 +882,6 @@ public class WifiManagerTest {
}
/**
- * Verify main looper is used when handler is not provided.
- */
- @Test
- public void registerSoftApCallbackUsesMainExecutorOnNoExecutorProvided() {
- when(mContext.getMainExecutor()).thenReturn(
- new HandlerExecutor(new Handler(mLooper.getLooper())));
- mWifiManager.registerSoftApCallback(mSoftApCallback);
- verify(mContext).getMainExecutor();
- }
-
- /**
* Verify the call to registerSoftApCallback goes to WifiServiceImpl.
*/
@Test
@@ -1389,11 +1379,10 @@ public class WifiManagerTest {
@Test
public void registerTrafficStateCallbackUsesMainLooperOnNullArgumentForHandler()
throws Exception {
- when(mContext.getMainExecutor()).thenReturn(
- new HandlerExecutor(new Handler(mLooper.getLooper())));
ArgumentCaptor<ITrafficStateCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(ITrafficStateCallback.Stub.class);
- mWifiManager.registerTrafficStateCallback(mTrafficStateCallback);
+ mWifiManager.registerTrafficStateCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())), mTrafficStateCallback);
verify(mWifiService).registerTrafficStateCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1474,11 +1463,11 @@ public class WifiManagerTest {
@Test
public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
throws Exception {
- when(mContext.getMainExecutor()).thenReturn(
- new HandlerExecutor(new Handler(mLooper.getLooper())));
ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
- mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+ mWifiManager.registerNetworkRequestMatchCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())),
+ mNetworkRequestMatchCallback);
verify(mWifiService).registerNetworkRequestMatchCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1530,11 +1519,11 @@ public class WifiManagerTest {
@Test
public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
throws Exception {
- when(mContext.getMainExecutor()).thenReturn(
- new HandlerExecutor(new Handler(mLooper.getLooper())));
ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
- mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+ mWifiManager.registerNetworkRequestMatchCallback(
+ new HandlerExecutor(new Handler(mLooper.getLooper())),
+ mNetworkRequestMatchCallback);
verify(mWifiService).registerNetworkRequestMatchCallback(
any(IBinder.class), callbackCaptor.capture(), anyInt());
@@ -1808,6 +1797,16 @@ public class WifiManagerTest {
verify(mWifiService).setMacRandomizationSettingPasspointEnabled(fqdn, true);
}
+ /**
+ * Test behavior of
+ * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)}
+ */
+ @Test
+ public void testSetMeteredOverridePasspoint() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.setMeteredOverridePasspoint(fqdn, METERED_OVERRIDE_METERED);
+ verify(mWifiService).setMeteredOverridePasspoint(fqdn, METERED_OVERRIDE_METERED);
+ }
/**
* Test behavior of {@link WifiManager#disconnect()}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 603e78b90ff2..654154d77b0d 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -16,6 +16,8 @@
package android.net.wifi.hotspot2;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -173,6 +175,7 @@ public class PasspointConfigurationTest {
assertFalse(config.validateForR2());
assertTrue(config.isAutoJoinEnabled());
assertTrue(config.isMacRandomizationEnabled());
+ assertTrue(config.getMeteredOverride() == METERED_OVERRIDE_NONE);
}
/**