summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp21
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java12
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java17
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java202
-rw-r--r--apex/sdkextensions/Android.bp8
-rw-r--r--apex/sdkextensions/ld.config.txt31
-rw-r--r--apex/statsd/framework/java/android/app/StatsManager.java15
-rw-r--r--api/current.txt60
-rw-r--r--api/module-lib-current.txt1
-rw-r--r--api/module-lib-lint-baseline.txt4
-rwxr-xr-xapi/system-current.txt15
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp16
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java4
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityShortcutInfo.java3
-rw-r--r--core/java/android/app/ContextImpl.java20
-rw-r--r--core/java/android/app/IWindowToken.aidl33
-rw-r--r--core/java/android/app/KeyguardManager.java24
-rw-r--r--core/java/android/app/WindowContext.java57
-rw-r--r--core/java/android/app/WindowTokenClient.java76
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java99
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/admin/SecurityLog.java140
-rw-r--r--core/java/android/app/admin/SecurityLogTags.logtags4
-rw-r--r--core/java/android/app/trust/IStrongAuthTracker.aidl1
-rw-r--r--core/java/android/content/ContentProvider.java9
-rw-r--r--core/java/android/content/ContentProviderNative.java29
-rw-r--r--core/java/android/content/ContentResolver.java53
-rw-r--r--core/java/android/content/IContentProvider.java11
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl6
-rw-r--r--core/java/android/content/pm/LauncherApps.java23
-rw-r--r--core/java/android/content/pm/ShortcutServiceInternal.java3
-rw-r--r--core/java/android/hardware/display/DeviceProductInfo.java18
-rw-r--r--core/java/android/hardware/face/FaceManager.java28
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl3
-rw-r--r--core/java/android/hardware/face/IFaceServiceReceiver.aidl3
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java27
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl3
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl3
-rw-r--r--core/java/android/hardware/iris/IIrisService.aidl4
-rw-r--r--core/java/android/net/NetworkScore.java107
-rw-r--r--core/java/android/os/CoolingDevice.aidl2
-rw-r--r--core/java/android/os/IThermalService.aidl9
-rw-r--r--core/java/android/os/Temperature.aidl2
-rw-r--r--core/java/android/os/UserManager.java41
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/service/controls/ControlsProviderService.java44
-rw-r--r--core/java/android/util/EventLog.java110
-rw-r--r--core/java/android/util/FeatureFlagUtils.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java24
-rw-r--r--core/java/android/view/WindowManager.java2
-rw-r--r--core/java/com/android/internal/app/ResolverViewPager.java14
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java22
-rw-r--r--core/java/com/android/internal/content/om/TEST_MAPPING12
-rw-r--r--core/java/com/android/internal/policy/DecorContext.java3
-rw-r--r--core/java/com/android/internal/util/FunctionalUtils.java20
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java76
-rw-r--r--core/jni/Android.bp162
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/LayoutlibLoader.cpp76
-rw-r--r--core/jni/android_graphics_GraphicBuffer.cpp16
-rw-r--r--core/jni/android_graphics_SurfaceTexture.cpp (renamed from core/jni/android/graphics/SurfaceTexture.cpp)1
-rw-r--r--core/jni/core_jni_helpers.h12
-rw-r--r--core/proto/android/server/peopleservice.proto3
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/layout/chooser_grid.xml2
-rw-r--r--core/res/res/values/config.xml35
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java2
-rw-r--r--core/tests/coretests/src/android/content/ContentResolverTest.java8
-rw-r--r--core/tests/coretests/src/android/content/FakeProviderRemote.java6
-rw-r--r--core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java35
-rw-r--r--core/tests/coretests/src/android/util/EventLogTest.java74
-rw-r--r--data/etc/services.core.protolog.json12
-rw-r--r--graphics/java/android/graphics/Bitmap.java3
-rw-r--r--graphics/java/android/graphics/GraphicBuffer.java10
-rw-r--r--graphics/java/android/graphics/Outline.java5
-rw-r--r--keystore/java/android/security/KeyChain.java5
-rw-r--r--libs/hwui/Android.bp232
-rw-r--r--libs/hwui/DeviceInfo.cpp3
-rw-r--r--libs/hwui/apex/LayoutlibLoader.cpp191
-rw-r--r--libs/hwui/apex/TypeCast.h (renamed from core/jni/android/graphics/apex/TypeCast.h)0
-rw-r--r--libs/hwui/apex/android_bitmap.cpp (renamed from core/jni/android/graphics/apex/android_bitmap.cpp)1
-rw-r--r--libs/hwui/apex/android_canvas.cpp (renamed from core/jni/android/graphics/apex/android_canvas.cpp)0
-rw-r--r--libs/hwui/apex/android_matrix.cpp (renamed from core/jni/android/graphics/apex/android_matrix.cpp)2
-rw-r--r--libs/hwui/apex/android_paint.cpp (renamed from core/jni/android/graphics/apex/android_paint.cpp)0
-rw-r--r--libs/hwui/apex/android_region.cpp (renamed from core/jni/android/graphics/apex/android_region.cpp)0
-rw-r--r--libs/hwui/apex/include/android/graphics/bitmap.h (renamed from core/jni/android/graphics/apex/include/android/graphics/bitmap.h)27
-rw-r--r--libs/hwui/apex/include/android/graphics/canvas.h (renamed from core/jni/android/graphics/apex/include/android/graphics/canvas.h)19
-rw-r--r--libs/hwui/apex/include/android/graphics/jni_runtime.h (renamed from core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h)9
-rw-r--r--libs/hwui/apex/include/android/graphics/matrix.h (renamed from core/jni/android/graphics/apex/include/android/graphics/matrix.h)3
-rw-r--r--libs/hwui/apex/include/android/graphics/paint.h (renamed from core/jni/android/graphics/apex/include/android/graphics/paint.h)7
-rw-r--r--libs/hwui/apex/include/android/graphics/region.h (renamed from core/jni/android/graphics/apex/include/android/graphics/region.h)15
-rw-r--r--libs/hwui/apex/include/android/graphics/renderthread.h (renamed from core/jni/android/graphics/apex/include/android/graphics/renderthread.h)3
-rw-r--r--libs/hwui/apex/jni_runtime.cpp (renamed from core/jni/android/graphics/apex/jni_runtime.cpp)8
-rw-r--r--libs/hwui/apex/renderthread.cpp (renamed from core/jni/android/graphics/apex/renderthread.cpp)0
-rw-r--r--libs/hwui/hwui/Bitmap.cpp14
-rw-r--r--libs/hwui/hwui/Bitmap.h6
-rw-r--r--libs/hwui/jni/AnimatedImageDrawable.cpp (renamed from core/jni/android/graphics/AnimatedImageDrawable.cpp)1
-rwxr-xr-xlibs/hwui/jni/Bitmap.cpp (renamed from core/jni/android/graphics/Bitmap.cpp)52
-rw-r--r--libs/hwui/jni/Bitmap.h (renamed from core/jni/android/graphics/Bitmap.h)0
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp (renamed from core/jni/android/graphics/BitmapFactory.cpp)11
-rw-r--r--libs/hwui/jni/BitmapFactory.h (renamed from core/jni/android/graphics/BitmapFactory.h)0
-rw-r--r--libs/hwui/jni/BitmapRegionDecoder.cpp (renamed from core/jni/android/graphics/BitmapRegionDecoder.cpp)5
-rw-r--r--libs/hwui/jni/ByteBufferStreamAdaptor.cpp (renamed from core/jni/android/graphics/ByteBufferStreamAdaptor.cpp)3
-rw-r--r--libs/hwui/jni/ByteBufferStreamAdaptor.h (renamed from core/jni/android/graphics/ByteBufferStreamAdaptor.h)0
-rw-r--r--libs/hwui/jni/Camera.cpp (renamed from core/jni/android/graphics/Camera.cpp)3
-rw-r--r--libs/hwui/jni/CanvasProperty.cpp (renamed from core/jni/android/graphics/CanvasProperty.cpp)2
-rw-r--r--libs/hwui/jni/ColorFilter.cpp (renamed from core/jni/android/graphics/ColorFilter.cpp)2
-rw-r--r--libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp (renamed from core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp)0
-rw-r--r--libs/hwui/jni/CreateJavaOutputStreamAdaptor.h (renamed from core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h)1
-rw-r--r--libs/hwui/jni/FontFamily.cpp (renamed from core/jni/android/graphics/FontFamily.cpp)17
-rw-r--r--libs/hwui/jni/FontUtils.cpp (renamed from core/jni/android/graphics/FontUtils.cpp)3
-rw-r--r--libs/hwui/jni/FontUtils.h (renamed from core/jni/android/graphics/FontUtils.h)0
-rw-r--r--libs/hwui/jni/GIFMovie.cpp (renamed from core/jni/android/graphics/GIFMovie.cpp)0
-rw-r--r--libs/hwui/jni/Graphics.cpp (renamed from core/jni/android/graphics/Graphics.cpp)39
-rw-r--r--libs/hwui/jni/GraphicsJNI.h (renamed from core/jni/android/graphics/GraphicsJNI.h)25
-rw-r--r--libs/hwui/jni/GraphicsStatsService.cpp (renamed from core/jni/android/graphics/GraphicsStatsService.cpp)14
-rw-r--r--libs/hwui/jni/ImageDecoder.cpp (renamed from core/jni/android/graphics/ImageDecoder.cpp)7
-rw-r--r--libs/hwui/jni/ImageDecoder.h (renamed from core/jni/android/graphics/ImageDecoder.h)0
-rw-r--r--libs/hwui/jni/Interpolator.cpp (renamed from core/jni/android/graphics/Interpolator.cpp)3
-rw-r--r--libs/hwui/jni/MaskFilter.cpp (renamed from core/jni/android/graphics/MaskFilter.cpp)4
-rw-r--r--libs/hwui/jni/MimeType.h (renamed from core/jni/android/graphics/MimeType.h)3
-rw-r--r--libs/hwui/jni/Movie.cpp (renamed from core/jni/android/graphics/Movie.cpp)2
-rw-r--r--libs/hwui/jni/Movie.h (renamed from core/jni/android/graphics/Movie.h)0
-rw-r--r--libs/hwui/jni/MovieImpl.cpp (renamed from core/jni/android/graphics/MovieImpl.cpp)0
-rw-r--r--libs/hwui/jni/NinePatch.cpp (renamed from core/jni/android/graphics/NinePatch.cpp)4
-rw-r--r--libs/hwui/jni/NinePatchPeeker.cpp (renamed from core/jni/android/graphics/NinePatchPeeker.cpp)0
-rw-r--r--libs/hwui/jni/NinePatchPeeker.h (renamed from core/jni/android/graphics/NinePatchPeeker.h)0
-rw-r--r--libs/hwui/jni/Paint.cpp (renamed from core/jni/android/graphics/Paint.cpp)3
-rw-r--r--libs/hwui/jni/PaintFilter.cpp (renamed from core/jni/android/graphics/PaintFilter.cpp)4
-rw-r--r--libs/hwui/jni/Path.cpp (renamed from core/jni/android/graphics/Path.cpp)2
-rw-r--r--libs/hwui/jni/PathEffect.cpp (renamed from core/jni/android/graphics/PathEffect.cpp)3
-rw-r--r--libs/hwui/jni/PathMeasure.cpp (renamed from core/jni/android/graphics/PathMeasure.cpp)2
-rw-r--r--libs/hwui/jni/Picture.cpp (renamed from core/jni/android/graphics/Picture.cpp)0
-rw-r--r--libs/hwui/jni/Picture.h (renamed from core/jni/android/graphics/Picture.h)0
-rw-r--r--libs/hwui/jni/Region.cpp (renamed from core/jni/android/graphics/Region.cpp)23
-rw-r--r--libs/hwui/jni/RtlProperties.h (renamed from core/jni/android/graphics/RtlProperties.h)0
-rw-r--r--libs/hwui/jni/Shader.cpp (renamed from core/jni/android/graphics/Shader.cpp)3
-rw-r--r--libs/hwui/jni/TEST_MAPPING (renamed from core/jni/android/graphics/TEST_MAPPING)0
-rw-r--r--libs/hwui/jni/Typeface.cpp (renamed from core/jni/android/graphics/Typeface.cpp)3
-rw-r--r--libs/hwui/jni/Utils.cpp (renamed from core/jni/android/graphics/Utils.cpp)0
-rw-r--r--libs/hwui/jni/Utils.h (renamed from core/jni/android/graphics/Utils.h)0
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.cpp (renamed from core/jni/android/graphics/YuvToJpegEncoder.cpp)4
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.h (renamed from core/jni/android/graphics/YuvToJpegEncoder.h)0
-rw-r--r--libs/hwui/jni/android_graphics_Canvas.cpp (renamed from core/jni/android_graphics_Canvas.cpp)2
-rw-r--r--libs/hwui/jni/android_graphics_ColorSpace.cpp (renamed from core/jni/android_graphics_ColorSpace.cpp)13
-rw-r--r--libs/hwui/jni/android_graphics_DisplayListCanvas.cpp (renamed from core/jni/android_view_DisplayListCanvas.cpp)7
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp (renamed from core/jni/android_view_ThreadedRenderer.cpp)3
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp (renamed from core/jni/android_graphics_HardwareRendererObserver.cpp)2
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRendererObserver.h (renamed from core/jni/android_graphics_HardwareRendererObserver.h)0
-rw-r--r--libs/hwui/jni/android_graphics_Matrix.cpp (renamed from core/jni/android/graphics/Matrix.cpp)3
-rw-r--r--libs/hwui/jni/android_graphics_Matrix.h (renamed from core/jni/android/graphics/Matrix.h)0
-rw-r--r--libs/hwui/jni/android_graphics_Picture.cpp (renamed from core/jni/android_graphics_Picture.cpp)5
-rw-r--r--libs/hwui/jni/android_graphics_RenderNode.cpp (renamed from core/jni/android_view_RenderNode.cpp)6
-rw-r--r--libs/hwui/jni/android_graphics_TextureLayer.cpp (renamed from core/jni/android_view_TextureLayer.cpp)7
-rw-r--r--libs/hwui/jni/android_graphics_animation_NativeInterpolatorFactory.cpp (renamed from core/jni/android_graphics_animation_NativeInterpolatorFactory.cpp)6
-rw-r--r--libs/hwui/jni/android_graphics_animation_RenderNodeAnimator.cpp (renamed from core/jni/android_graphics_animation_RenderNodeAnimator.cpp)6
-rw-r--r--libs/hwui/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp (renamed from core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp)3
-rw-r--r--libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp (renamed from core/jni/android_graphics_drawable_VectorDrawable.cpp)2
-rw-r--r--libs/hwui/jni/android_nio_utils.cpp (renamed from core/jni/android_nio_utils.cpp)2
-rw-r--r--libs/hwui/jni/android_nio_utils.h (renamed from core/jni/android_nio_utils.h)0
-rw-r--r--libs/hwui/jni/android_util_PathParser.cpp (renamed from core/jni/android_util_PathParser.cpp)2
-rw-r--r--libs/hwui/jni/fonts/Font.cpp (renamed from core/jni/android/graphics/fonts/Font.cpp)18
-rw-r--r--libs/hwui/jni/fonts/FontFamily.cpp (renamed from core/jni/android/graphics/fonts/FontFamily.cpp)4
-rw-r--r--libs/hwui/jni/graphics_jni_helpers.h106
-rw-r--r--libs/hwui/jni/pdf/PdfDocument.cpp (renamed from core/jni/android/graphics/pdf/PdfDocument.cpp)2
-rw-r--r--libs/hwui/jni/pdf/PdfEditor.cpp (renamed from core/jni/android/graphics/pdf/PdfEditor.cpp)7
-rw-r--r--libs/hwui/jni/pdf/PdfRenderer.cpp (renamed from core/jni/android/graphics/pdf/PdfRenderer.cpp)3
-rw-r--r--libs/hwui/jni/pdf/PdfUtils.cpp (renamed from core/jni/android/graphics/pdf/PdfUtils.cpp)1
-rw-r--r--libs/hwui/jni/pdf/PdfUtils.h (renamed from core/jni/android/graphics/pdf/PdfUtils.h)0
-rw-r--r--libs/hwui/jni/scoped_nullable_primitive_array.h103
-rw-r--r--libs/hwui/jni/text/LineBreaker.cpp (renamed from core/jni/android/graphics/text/LineBreaker.cpp)4
-rw-r--r--libs/hwui/jni/text/MeasuredText.cpp (renamed from core/jni/android/graphics/text/MeasuredText.cpp)3
-rw-r--r--libs/input/Android.bp1
-rw-r--r--libs/input/tests/Android.bp1
-rw-r--r--location/java/android/location/LocationManager.java48
-rw-r--r--location/java/android/location/LocationManagerInternal.java16
-rw-r--r--location/java/com/android/internal/location/ILocationProvider.aidl2
-rw-r--r--location/lib/api/current.txt1
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java16
-rw-r--r--media/java/android/media/AudioManager.java6
-rw-r--r--media/java/android/media/IMediaRoute2ProviderService.aidl12
-rw-r--r--media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl1
-rw-r--r--media/java/android/media/IMediaRouter2Manager.aidl1
-rw-r--r--media/java/android/media/IMediaRouterService.aidl13
-rw-r--r--media/java/android/media/MediaCodec.java229
-rw-r--r--media/java/android/media/MediaRoute2Info.java177
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java150
-rw-r--r--media/java/android/media/MediaRouter2.java16
-rw-r--r--media/java/android/media/MediaRouter2Manager.java46
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java64
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java39
-rw-r--r--native/android/Android.bp4
-rw-r--r--native/android/libandroid.map.txt5
-rw-r--r--native/android/thermal.cpp261
-rw-r--r--native/graphics/jni/Android.bp2
-rw-r--r--native/graphics/jni/imagedecoder.cpp2
-rw-r--r--native/webview/plat_support/Android.bp4
-rw-r--r--native/webview/plat_support/graphics_utils.cpp4
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java5
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml22
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_activity.xml3
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_button.xml6
-rw-r--r--packages/SystemUI/res/layout/people_strip.xml43
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_footer.xml11
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml19
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml32
-rw-r--r--packages/SystemUI/res/values/dimens.xml12
-rw-r--r--packages/SystemUI/res/values/strings.xml21
-rw-r--r--packages/SystemUI/res/values/styles.xml10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java32
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java105
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/CornerHandleView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/LatencyTester.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java382
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt618
-rw-r--r--packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java113
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt442
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java3
-rw-r--r--rs/jni/Android.mk1
-rw-r--r--services/Android.bp2
-rw-r--r--services/api/current.txt9
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java55
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java7
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java27
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java65
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java25
-rw-r--r--services/core/java/com/android/server/MemoryPressureUtil.java56
-rw-r--r--services/core/java/com/android/server/SystemServerInitThreadPool.java2
-rw-r--r--services/core/java/com/android/server/Watchdog.java14
-rw-r--r--services/core/java/com/android/server/adb/AdbService.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java34
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java1
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java16
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java8
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java3
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java16
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java8
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java11
-rw-r--r--services/core/java/com/android/server/biometrics/iris/IrisService.java15
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java67
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkRanker.java76
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java14
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java15
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java5
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java8
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java5
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java9
-rw-r--r--services/core/java/com/android/server/location/PassiveProvider.java5
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java24
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java288
-rw-r--r--services/core/java/com/android/server/media/BluetoothRouteProvider.java3
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java13
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java77
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java190
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java25
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java16
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java11
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java55
-rw-r--r--services/core/java/com/android/server/pm/Installer.java4
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java183
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java189
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java17
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java34
-rw-r--r--services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java13
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java186
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java4
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java31
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java300
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java60
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp3
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp1
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java150
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java21
-rw-r--r--services/people/java/com/android/server/people/data/ConversationInfo.java8
-rw-r--r--services/people/java/com/android/server/people/data/ConversationStore.java26
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java56
-rw-r--r--services/people/java/com/android/server/people/data/PackageData.java11
-rw-r--r--services/people/java/com/android/server/people/data/UserData.java10
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java147
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java77
-rw-r--r--services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java69
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java67
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java21
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java47
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java79
-rw-r--r--services/wifi/Android.bp13
-rw-r--r--services/wifi/java/com/android/server/wifi/SupplicantManager.java47
-rw-r--r--test-mock/src/android/test/mock/MockContentProvider.java18
-rw-r--r--test-mock/src/android/test/mock/MockIContentProvider.java15
-rw-r--r--tests/net/common/java/android/net/NetworkScoreTest.kt40
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java11
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt30
-rwxr-xr-xtools/hiddenapi/merge_csv.py56
-rw-r--r--wifi/Android.bp1
-rw-r--r--wifi/java/android/net/wifi/SoftApCapability.java20
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java1
-rw-r--r--wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java19
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java4
376 files changed, 8036 insertions, 2873 deletions
diff --git a/Android.bp b/Android.bp
index a1f72fef942b..82e1a867786f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -451,6 +451,18 @@ filegroup {
path: "core/java",
}
+filegroup {
+ name: "libpowermanager_aidl",
+ srcs: [
+ "core/java/android/os/Temperature.aidl",
+ "core/java/android/os/CoolingDevice.aidl",
+ "core/java/android/os/IThermalEventListener.aidl",
+ "core/java/android/os/IThermalStatusListener.aidl",
+ "core/java/android/os/IThermalService.aidl",
+ ],
+ path: "core/java",
+}
+
java_library {
name: "framework-minus-apex",
defaults: ["framework-defaults"],
@@ -461,7 +473,6 @@ java_library {
"framework-statsd-stubs-module_libs_api",
"framework-permission-stubs-systemapi",
"framework-wifi-stubs",
- "ike-stubs",
"framework-tethering-stubs",
],
installable: true,
@@ -512,7 +523,6 @@ java_library {
"framework-sdkextensions-stubs-systemapi",
"framework-statsd-stubs-module_libs_api",
"framework-wifi-stubs",
- "ike-stubs",
"framework-tethering-stubs",
// TODO (b/147688669) should be framework-telephony-stubs
"framework-telephony",
@@ -689,6 +699,7 @@ filegroup {
"core/java/android/annotation/CurrentTimeMillisLong.java",
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
+ "core/java/android/annotation/LongDef.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/RequiresPermission.java",
@@ -1216,6 +1227,12 @@ java_library {
visibility: ["//frameworks/base/wifi"],
}
+filegroup {
+ name: "framework-wifi-util-lib-aidls",
+ srcs: ["core/java/android/content/pm/ParceledListSlice.aidl"],
+ path: "core/java",
+}
+
// utility classes statically linked into wifi-service
filegroup {
name: "framework-wifi-service-shared-srcs",
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index aae33d7b0a89..18b1108aab3a 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -858,12 +858,9 @@ public class BlobStoreManagerService extends SystemService {
writeBlobsInfoAsync();
// Cleanup any stale sessions.
- final ArrayList<Integer> indicesToRemove = new ArrayList<>();
for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
- indicesToRemove.clear();
- for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
- final BlobStoreSession blobStoreSession = userSessions.valueAt(j);
+ userSessions.removeIf((sessionId, blobStoreSession) -> {
boolean shouldRemove = false;
// Cleanup sessions which haven't been modified in a while.
@@ -880,13 +877,10 @@ public class BlobStoreManagerService extends SystemService {
if (shouldRemove) {
blobStoreSession.getSessionFile().delete();
mActiveBlobIds.remove(blobStoreSession.getSessionId());
- indicesToRemove.add(j);
deletedBlobIds.add(blobStoreSession.getSessionId());
}
- }
- for (int j = 0; j < indicesToRemove.size(); ++j) {
- userSessions.removeAt(indicesToRemove.get(j));
- }
+ return shouldRemove;
+ });
}
if (LOGV) {
Slog.v(TAG, "Completed idle maintenance; deleted "
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index b96161aba758..4c98b5fd3b56 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -77,11 +77,11 @@ public class JobParameters implements Parcelable {
/**
* @hide
- * @deprecated use {@link #getReasonCodeDescription(int)}
*/
- @Deprecated
- public static String getReasonName(int reason) {
- switch (reason) {
+ // TODO(142420609): make it @SystemApi for mainline
+ @NonNull
+ public static String getReasonCodeDescription(int reasonCode) {
+ switch (reasonCode) {
case REASON_CANCELED: return "canceled";
case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
case REASON_PREEMPT: return "preempt";
@@ -89,7 +89,7 @@ public class JobParameters implements Parcelable {
case REASON_DEVICE_IDLE: return "device_idle";
case REASON_DEVICE_THERMAL: return "thermal";
case REASON_RESTRAINED: return "restrained";
- default: return "unknown:" + reason;
+ default: return "unknown:" + reasonCode;
}
}
@@ -100,13 +100,6 @@ public class JobParameters implements Parcelable {
return JOB_STOP_REASON_CODES;
}
- /** @hide */
- // @SystemApi TODO make it a system api for mainline
- @NonNull
- public static String getReasonCodeDescription(int reasonCode) {
- return getReasonName(reasonCode);
- }
-
@UnsupportedAppUsage
private final int jobId;
private final PersistableBundle extras;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
index e28e5bd6c53d..d05034797f3d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java
@@ -359,7 +359,8 @@ public final class JobPackageTracker {
}
pw.print(pe.stopReasons.valueAt(k));
pw.print("x ");
- pw.print(JobParameters.getReasonName(pe.stopReasons.keyAt(k)));
+ pw.print(JobParameters
+ .getReasonCodeDescription(pe.stopReasons.keyAt(k)));
}
pw.println();
}
@@ -606,8 +607,9 @@ public final class JobPackageTracker {
if (reason != null) {
pw.print(mEventReasons[index]);
} else {
- pw.print(JobParameters.getReasonName((mEventCmds[index] & EVENT_STOP_REASON_MASK)
- >> EVENT_STOP_REASON_SHIFT));
+ pw.print(JobParameters.getReasonCodeDescription(
+ (mEventCmds[index] & EVENT_STOP_REASON_MASK)
+ >> EVENT_STOP_REASON_SHIFT));
}
}
pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index ff7944d07310..c1e529f3f966 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1963,7 +1963,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (restriction != null) {
final int reason = restriction.getReason();
serviceContext.cancelExecutingJobLocked(reason,
- "restricted due to " + JobParameters.getReasonName(reason));
+ "restricted due to " + JobParameters.getReasonCodeDescription(reason));
}
}
}
@@ -3110,7 +3110,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final JobRestriction restriction = mJobRestrictions.get(i);
if (restriction.isJobRestricted(job)) {
final int reason = restriction.getReason();
- pw.write(" " + JobParameters.getReasonName(reason) + "[" + reason + "]");
+ pw.print(" " + JobParameters.getReasonCodeDescription(reason));
}
}
} else {
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 1ae0c22541c2..11d3a6867ac3 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -56,6 +56,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -404,9 +405,141 @@ public final class MediaParser {
}
}
+ // Public constants.
+
+ /**
+ * Sets whether constant bitrate seeking should be enabled for exo.AdtsParser. {@code boolean}
+ * expected. Default value is {@code false}.
+ */
+ public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING =
+ "exo.AdtsParser.enableCbrSeeking";
+ /**
+ * Sets whether constant bitrate seeking should be enabled for exo.AmrParser. {@code boolean}
+ * expected. Default value is {@code false}.
+ */
+ public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking";
+ /**
+ * Sets whether the ID3 track should be disabled for exo.FlacParser. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3";
+ /**
+ * Sets whether exo.FragmentedMp4Parser should ignore edit lists. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS =
+ "exo.FragmentedMp4Parser.ignoreEditLists";
+ /**
+ * Sets whether exo.FragmentedMp4Parser should ignore the tfdt box. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX =
+ "exo.FragmentedMp4Parser.ignoreTfdtBox";
+ /**
+ * Sets whether exo.FragmentedMp4Parser should treat all video frames as key frames. {@code
+ * boolean} expected. Default value is {@code false}.
+ */
+ public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES =
+ "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes";
+ /**
+ * Sets whether exo.MatroskaParser should avoid seeking to the cues element. {@code boolean}
+ * expected. Default value is {@code false}.
+ *
+ * <p>If this flag is enabled and the cues element occurs after the first cluster, then the
+ * media is treated as unseekable.
+ */
+ public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING =
+ "exo.MatroskaParser.disableCuesSeeking";
+ /**
+ * Sets whether the ID3 track should be disabled for exo.Mp3Parser. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3";
+ /**
+ * Sets whether constant bitrate seeking should be enabled for exo.Mp3Parser. {@code boolean}
+ * expected. Default value is {@code false}.
+ */
+ public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking";
+ /**
+ * Sets whether exo.Mp3Parser should generate a time-to-byte mapping. {@code boolean} expected.
+ * Default value is {@code false}.
+ *
+ * <p>Enabling this flag may require to scan a significant portion of the file to compute a seek
+ * point. Therefore, it should only be used if:
+ *
+ * <ul>
+ * <li>the file is small, or
+ * <li>the bitrate is variable (or the type of bitrate is unknown) and the seeking metadata
+ * provided in the file is not precise enough (or is not present).
+ * </ul>
+ */
+ public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING =
+ "exo.Mp3Parser.enableIndexSeeking";
+ /**
+ * Sets whether exo.Mp4Parser should ignore edit lists. {@code boolean} expected. Default value
+ * is {@code false}.
+ */
+ public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists";
+ /**
+ * Sets the operation mode for exo.TsParser. {@code String} expected. Valid values are {@code
+ * "single_pmt"}, {@code "multi_pmt"}, and {@code "hls"}. Default value is {@code "single_pmt"}.
+ *
+ * <p>The operation modes alter the way exo.TsParser behaves so that it can handle certain kinds
+ * of commonly-occurring malformed media.
+ *
+ * <ul>
+ * <li>{@code "single_pmt"}: Only the first found PMT is parsed. Others are ignored, even if
+ * more PMTs are declared in the PAT.
+ * <li>{@code "multi_pmt"}: Behave as described in ISO/IEC 13818-1.
+ * <li>{@code "hls"}: Enable {@code "single_pmt"} mode, and ignore continuity counters.
+ * </ul>
+ */
+ public static final String PARAMETER_TS_MODE = "exo.TsParser.mode";
+ /**
+ * Sets whether exo.TsParser should treat samples consisting of non-IDR I slices as
+ * synchronization samples (key-frames). {@code boolean} expected. Default value is {@code
+ * false}.
+ */
+ public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES =
+ "exo.TsParser.allowNonIdrAvcKeyframes";
+ /**
+ * Sets whether exo.TsParser should ignore AAC elementary streams. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream";
+ /**
+ * Sets whether exo.TsParser should ignore AVC elementary streams. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream";
+ /**
+ * Sets whether exo.TsParser should ignore splice information streams. {@code boolean} expected.
+ * Default value is {@code false}.
+ */
+ public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM =
+ "exo.TsParser.ignoreSpliceInfoStream";
+ /**
+ * Sets whether exo.TsParser should split AVC stream into access units based on slice headers.
+ * {@code boolean} expected. Default value is {@code false}.
+ *
+ * <p>This flag should be left disabled if the stream contains access units delimiters in order
+ * to avoid unnecessary computational costs.
+ */
+ public static final String PARAMETER_TS_DETECT_ACCESS_UNITS =
+ "exo.TsParser.ignoreDetectAccessUnits";
+ /**
+ * Sets whether exo.TsParser should handle HDMV DTS audio streams. {@code boolean} expected.
+ * Default value is {@code false}.
+ *
+ * <p>Enabling this flag will disable the detection of SCTE subtitles.
+ */
+ public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS =
+ "exo.TsParser.enableHdmvDtsAudioStreams";
+
// Private constants.
private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
+ private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
// Instance creation methods.
@@ -462,6 +595,7 @@ public final class MediaParser {
// Private fields.
+ private final Map<String, Object> mParserParameters;
private final OutputConsumer mOutputConsumer;
private final String[] mParserNamesPool;
private final PositionHolder mPositionHolder;
@@ -477,6 +611,51 @@ public final class MediaParser {
// Public methods.
/**
+ * Sets parser-specific parameters which allow customizing behavior.
+ *
+ * <p>Must be called before the first call to {@link #advance}.
+ *
+ * @param parameterName The name of the parameter to set. See {@code PARAMETER_*} constants for
+ * documentation on possible values.
+ * @param value The value to set for the given {@code parameterName}. See {@code PARAMETER_*}
+ * constants for documentation on the expected types.
+ * @return This instance, for convenience.
+ * @throws IllegalStateException If called after calling {@link #advance} on the same instance.
+ */
+ @NonNull
+ public MediaParser setParameter(@NonNull String parameterName, @NonNull Object value) {
+ if (mExtractor != null) {
+ throw new IllegalStateException(
+ "setParameters() must be called before the first advance() call.");
+ }
+ Class expectedType = EXPECTED_TYPE_BY_PARAMETER_NAME.get(parameterName);
+ // Ignore parameter names that are not contained in the map, in case the client is passing
+ // a parameter that is being added in a future version of this library.
+ if (expectedType != null && !expectedType.isInstance(value)) {
+ throw new IllegalArgumentException(
+ parameterName
+ + " expects a "
+ + expectedType.getSimpleName()
+ + " but a "
+ + value.getClass().getSimpleName()
+ + " was passed.");
+ }
+ mParserParameters.put(parameterName, value);
+ return this;
+ }
+
+ /**
+ * Returns whether the given {@code parameterName} is supported by this parser.
+ *
+ * @param parameterName The parameter name to check support for. One of the {@code PARAMETER_*}
+ * constants.
+ * @return Whether the given {@code parameterName} is supported.
+ */
+ public boolean supportsParameter(@NonNull String parameterName) {
+ return EXPECTED_TYPE_BY_PARAMETER_NAME.containsKey(parameterName);
+ }
+
+ /**
* Returns the name of the backing parser implementation.
*
* <p>If this instance was creating using {@link #createByName}, the provided name is returned.
@@ -599,6 +778,7 @@ public final class MediaParser {
// Private methods.
private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
+ mParserParameters = new HashMap<>();
mOutputConsumer = outputConsumer;
mParserNamesPool = parserNamesPool;
if (!sniff) {
@@ -949,5 +1129,27 @@ public final class MediaParser {
extractorFactoriesByName.put("exo.TsParser", TsExtractor::new);
extractorFactoriesByName.put("exo.WavParser", WavExtractor::new);
EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
+
+ HashMap<String, Class> expectedTypeByParameterName = new HashMap<>();
+ expectedTypeByParameterName.put(PARAMETER_ADTS_ENABLE_CBR_SEEKING, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_AMR_ENABLE_CBR_SEEKING, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_FLAC_DISABLE_ID3, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_EDIT_LISTS, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_TFDT_BOX, Boolean.class);
+ expectedTypeByParameterName.put(
+ PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_MP3_DISABLE_ID3, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_CBR_SEEKING, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_INDEX_SEEKING, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_MODE, String.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AAC_STREAM, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AVC_STREAM, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_DETECT_ACCESS_UNITS, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, Boolean.class);
+ EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
}
}
diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp
index 4c5c2b2cfd4f..25765afb3ab9 100644
--- a/apex/sdkextensions/Android.bp
+++ b/apex/sdkextensions/Android.bp
@@ -28,7 +28,6 @@ apex_defaults {
name: "com.android.sdkext-defaults",
java_libs: [ "framework-sdkextensions" ],
prebuilts: [
- "com.android.sdkext.ldconfig",
"derive_sdk.rc",
],
key: "com.android.sdkext.key",
@@ -51,13 +50,6 @@ android_app_certificate {
certificate: "com.android.sdkext",
}
-prebuilt_etc {
- name: "com.android.sdkext.ldconfig",
- src: "ld.config.txt",
- filename: "ld.config.txt",
- installable: false,
-}
-
python_binary_host {
name: "gen_sdkinfo",
srcs: [
diff --git a/apex/sdkextensions/ld.config.txt b/apex/sdkextensions/ld.config.txt
deleted file mode 100644
index dcc69b892760..000000000000
--- a/apex/sdkextensions/ld.config.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Bionic loader config file for the sdkextensions apex.
-
-dir.sdkextensions = /apex/com.android.sdkext/bin/
-
-[sdkextensions]
-additional.namespaces = platform
-
-namespace.default.isolated = true
-namespace.default.links = platform
-namespace.default.link.platform.allow_all_shared_libs = true
-
-###############################################################################
-# "platform" namespace: used for NDK libraries
-###############################################################################
-namespace.platform.isolated = true
-namespace.platform.search.paths = /system/${LIB}
-namespace.platform.asan.search.paths = /data/asan/system/${LIB}
-
-# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
-# Add /apex/... path to the permitted paths because linker uses realpath(3)
-# to check the accessibility of the lib. We could add this to search.paths
-# instead but that makes the resolution of bionic libs be dependent on
-# the order of /system/lib and /apex/... in search.paths. If /apex/...
-# is after /system/lib, then /apex/... is never tried because libc.so
-# is always found in /system/lib but fails to pass the accessibility test
-# because of its realpath. It's better to not depend on the ordering if
-# possible.
-namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
-namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 526d17ff0d71..e637187f23be 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -159,6 +159,9 @@ public final class StatsManager {
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to addConfig in statsmanager");
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -195,6 +198,9 @@ public final class StatsManager {
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to removeConfig in statsmanager");
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -391,6 +397,9 @@ public final class StatsManager {
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to getReports in statsmanager");
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -428,6 +437,9 @@ public final class StatsManager {
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to getStatsMetadata in statsmanager");
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -469,6 +481,9 @@ public final class StatsManager {
+ "registered experiment IDs");
}
throw new StatsUnavailableException("could not connect", e);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to getRegisteredExperimentIds in statsmanager");
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
diff --git a/api/current.txt b/api/current.txt
index 1e65e7bdfc9e..0a7bac5183dc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32,6 +32,7 @@ package android {
field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
+ field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
@@ -2991,7 +2992,7 @@ package android.accessibilityservice {
method public int getNonInteractiveUiTimeoutMillis();
method public android.content.pm.ResolveInfo getResolveInfo();
method public String getSettingsActivityName();
- method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.pm.PackageManager);
+ method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.Context);
method public String loadDescription(android.content.pm.PackageManager);
method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager);
method public CharSequence loadSummary(android.content.pm.PackageManager);
@@ -6969,7 +6970,6 @@ package android.app.admin {
method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
method public boolean requestBugreport(@NonNull android.content.ComponentName);
- method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean);
method @Deprecated public boolean resetPassword(String, int);
method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
@@ -25307,6 +25307,10 @@ package android.media {
method public void recycle();
}
+ public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException {
+ ctor public MediaCodec.IncompatibleWithBlockModelException();
+ }
+
public static final class MediaCodec.LinearBlock {
method protected void finalize();
method public static boolean isCodecCopyFreeCompatible(@NonNull String[]);
@@ -25334,23 +25338,24 @@ package android.media {
}
public static final class MediaCodec.OutputFrame {
- method public void getChangedKeys(@NonNull java.util.Set<java.lang.String>);
method public int getFlags();
method @NonNull public android.media.MediaFormat getFormat();
method @Nullable public android.media.MediaCodec.GraphicBlock getGraphicBlock();
method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
method public long getPresentationTimeUs();
+ method public void retrieveChangedKeys(@NonNull java.util.Set<java.lang.String>);
}
public final class MediaCodec.QueueRequest {
method public void queue();
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
- method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
method @NonNull public android.media.MediaCodec.QueueRequest setFloatParameter(@NonNull String, float);
- method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock);
method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
- method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, long, int);
+ method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
+ method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
}
@@ -26408,6 +26413,26 @@ package android.media {
method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat);
method public void release();
method public void seek(@NonNull android.media.MediaParser.SeekPoint);
+ method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object);
+ method public boolean supportsParameter(@NonNull String);
+ field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "exo.AdtsParser.enableCbrSeeking";
+ field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking";
+ field public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3";
+ field public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS = "exo.FragmentedMp4Parser.ignoreEditLists";
+ field public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX = "exo.FragmentedMp4Parser.ignoreTfdtBox";
+ field public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes";
+ field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "exo.MatroskaParser.disableCuesSeeking";
+ field public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3";
+ field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking";
+ field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "exo.Mp3Parser.enableIndexSeeking";
+ field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists";
+ field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "exo.TsParser.allowNonIdrAvcKeyframes";
+ field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "exo.TsParser.ignoreDetectAccessUnits";
+ field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "exo.TsParser.enableHdmvDtsAudioStreams";
+ field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream";
+ field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream";
+ field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "exo.TsParser.ignoreSpliceInfoStream";
+ field public static final String PARAMETER_TS_MODE = "exo.TsParser.mode";
}
public static interface MediaParser.InputReader {
@@ -26874,21 +26899,27 @@ package android.media {
ctor public MediaRoute2ProviderService();
method @NonNull public final java.util.List<android.media.RoutingSessionInfo> getAllSessionInfo();
method @Nullable public final android.media.RoutingSessionInfo getSessionInfo(@NonNull String);
+ method public final void notifyRequestFailed(long, int);
method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
method public final void notifySessionCreationFailed(long);
method public final void notifySessionReleased(@NonNull String);
method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onCreateSession(@NonNull String, @NonNull String, long, @Nullable android.os.Bundle);
- method public abstract void onDeselectRoute(@NonNull String, @NonNull String);
+ method public abstract void onCreateSession(long, @NonNull String, @NonNull String, @Nullable android.os.Bundle);
+ method public abstract void onDeselectRoute(long, @NonNull String, @NonNull String);
method public void onDiscoveryPreferenceChanged(@NonNull android.media.RouteDiscoveryPreference);
- method public abstract void onReleaseSession(@NonNull String);
- method public abstract void onSelectRoute(@NonNull String, @NonNull String);
- method public abstract void onSetRouteVolume(@NonNull String, int);
- method public abstract void onSetSessionVolume(@NonNull String, int);
- method public abstract void onTransferToRoute(@NonNull String, @NonNull String);
- field public static final long REQUEST_ID_UNKNOWN = 0L; // 0x0L
+ method public abstract void onReleaseSession(long, @NonNull String);
+ method public abstract void onSelectRoute(long, @NonNull String, @NonNull String);
+ method public abstract void onSetRouteVolume(long, @NonNull String, int);
+ method public abstract void onSetSessionVolume(long, @NonNull String, int);
+ method public abstract void onTransferToRoute(long, @NonNull String, @NonNull String);
+ field public static final int REASON_INVALID_COMMAND = 4; // 0x4
+ field public static final int REASON_NETWORK_ERROR = 2; // 0x2
+ field public static final int REASON_REJECTED = 1; // 0x1
+ field public static final int REASON_ROUTE_NOT_AVAILABLE = 3; // 0x3
+ field public static final int REASON_UNKNOWN_ERROR = 0; // 0x0
+ field public static final long REQUEST_ID_NONE = 0L; // 0x0L
field public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
}
@@ -43401,6 +43432,7 @@ package android.service.controls {
method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>);
method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable();
method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested();
+ method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control);
field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService";
field @NonNull public static final String TAG = "ControlsProviderService";
}
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 7b66f735b5ad..6863221f7fda 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -30,7 +30,6 @@ package android.net {
}
public class TetheringConstants {
- ctor public TetheringConstants();
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
diff --git a/api/module-lib-lint-baseline.txt b/api/module-lib-lint-baseline.txt
index 6e59596cb05f..56f7a02260a7 100644
--- a/api/module-lib-lint-baseline.txt
+++ b/api/module-lib-lint-baseline.txt
@@ -27,7 +27,3 @@ PrivateSuperclass: android.location.GnssAntennaInfo.PhaseCenterVariationCorrecti
Public class android.location.GnssAntennaInfo.PhaseCenterVariationCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
PrivateSuperclass: android.location.GnssAntennaInfo.SignalGainCorrections:
Public class android.location.GnssAntennaInfo.SignalGainCorrections extends private class android.location.GnssAntennaInfo.SphericalCorrections
-
-
-StaticUtils: android.net.TetheringConstants:
- Fully-static utility classes must not have constructor
diff --git a/api/system-current.txt b/api/system-current.txt
index 9663c0c53a39..2c6228c31932 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -630,10 +630,10 @@ package android.app {
method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence);
method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int);
method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed();
+ method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean isValidLockPasswordComplexity(int, @NonNull byte[], int);
method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int);
method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean);
- method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean validateLockPasswordComplexity(boolean, @NonNull byte[], int);
}
public class Notification implements android.os.Parcelable {
@@ -7200,12 +7200,12 @@ package android.net.wifi {
public final class SoftApCapability implements android.os.Parcelable {
method public int describeContents();
method public int getMaxSupportedClients();
- method public boolean isFeatureSupported(int);
+ method public boolean isFeatureSupported(long);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
- field public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1; // 0x1
- field public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2; // 0x2
- field public static final int SOFTAP_FEATURE_WPA3_SAE = 4; // 0x4
+ field public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1L; // 0x1L
+ field public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2L; // 0x2L
+ field public static final long SOFTAP_FEATURE_WPA3_SAE = 4L; // 0x4L
}
public final class SoftApConfiguration implements android.os.Parcelable {
@@ -8757,7 +8757,9 @@ package android.os {
public class UserManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
- method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @Nullable String[]) throws android.os.UserManager.UserOperationException;
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
@@ -8765,7 +8767,6 @@ package android.os {
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getUserProfiles(boolean);
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 4899b4a5247c..dcfdfe3aae53 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -75,11 +75,11 @@ string StorageManager::getDataHistoryFileName(long wallClockSec, int uid, int64_
(long long)id);
}
-static const char* findTrainInfoFileNameLocked(const string& trainName) {
+static string findTrainInfoFileNameLocked(const string& trainName) {
unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
if (dir == NULL) {
VLOG("Path %s does not exist", TRAIN_INFO_DIR);
- return nullptr;
+ return "";
}
dirent* de;
while ((de = readdir(dir.get()))) {
@@ -90,12 +90,12 @@ static const char* findTrainInfoFileNameLocked(const string& trainName) {
if (fileNameLength >= trainName.length()) {
if (0 == strncmp(fileName + fileNameLength - trainName.length(), trainName.c_str(),
trainName.length())) {
- return fileName;
+ return string(fileName);
}
}
}
- return nullptr;
+ return "";
}
// Returns array of int64_t which contains timestamp in seconds, uid,
@@ -267,13 +267,13 @@ bool StorageManager::readTrainInfo(const std::string& trainName, InstallTrainInf
bool StorageManager::readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo) {
trimToFit(TRAIN_INFO_DIR, /*parseTimestampOnly=*/ true);
- const char* fileName = findTrainInfoFileNameLocked(trainName);
- if (fileName == nullptr) {
+ string fileName = findTrainInfoFileNameLocked(trainName);
+ if (fileName.empty()) {
return false;
}
- int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName).c_str(), O_RDONLY | O_CLOEXEC);
+ int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName.c_str()).c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
- VLOG("Failed to open %s", fileName);
+ VLOG("Failed to open %s", fileName.c_str());
return false;
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 97074050448e..fe270a480d83 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -46,6 +46,10 @@ public final class Telecom extends BaseCommand {
* @param args The command-line arguments
*/
public static void main(String[] args) {
+ // Initialize the telephony module.
+ // TODO: Do it in zygote and RuntimeInit. b/148897549
+ ActivityThread.initializeMainlineModules();
+
(new Telecom()).run(args);
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index c37328454c7d..3b0667d1e377 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -803,11 +803,12 @@ public class AccessibilityServiceInfo implements Parcelable {
* @return The animated image drawable.
*/
@Nullable
- public Drawable loadAnimatedImage(@NonNull PackageManager packageManager) {
+ public Drawable loadAnimatedImage(@NonNull Context context) {
if (mAnimatedImageRes == /* invalid */ 0) {
return null;
}
+ final PackageManager packageManager = context.getPackageManager();
final String packageName = mComponentName.getPackageName();
final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo;
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index d537ce1253dc..62096792d764 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -208,11 +208,12 @@ public final class AccessibilityShortcutInfo {
* @return The animated image drawable.
*/
@Nullable
- public Drawable loadAnimatedImage(@NonNull PackageManager packageManager) {
+ public Drawable loadAnimatedImage(@NonNull Context context) {
if (mAnimatedImageRes == /* invalid */ 0) {
return null;
}
+ final PackageManager packageManager = context.getPackageManager();
final String packageName = mComponentName.getPackageName();
final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8df26cbbb4f4..480ea8a25f91 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2409,17 +2409,35 @@ class ContextImpl extends Context {
+ "other visual contexts, such as Activity or one created with "
+ "Context#createDisplayContext(Display)");
}
- return new WindowContext(this, null /* token */, type, options);
+ return new WindowContext(this, type, options);
}
ContextImpl createBaseWindowContext(IBinder token) {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
+
context.mIsAssociatedWithDisplay = true;
return context;
}
+ Resources createWindowContextResources() {
+ final String resDir = mPackageInfo.getResDir();
+ final String[] splitResDirs = mPackageInfo.getSplitResDirs();
+ final String[] overlayDirs = mPackageInfo.getOverlayDirs();
+ final String[] libDirs = mPackageInfo.getApplicationInfo().sharedLibraryFiles;
+ final int displayId = getDisplayId();
+ final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
+ ? mPackageInfo.getCompatibilityInfo()
+ : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ final List<ResourcesLoader> loaders = mResources.getLoaders();
+
+ // TODO(b/128338354): Rename to createTokenResources
+ return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs,
+ overlayDirs, libDirs, displayId, null /* overrideConfig */,
+ compatInfo, mClassLoader, loaders);
+ }
+
@Override
public @NonNull Context createFeatureContext(@Nullable String featureId) {
return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName,
diff --git a/core/java/android/app/IWindowToken.aidl b/core/java/android/app/IWindowToken.aidl
new file mode 100644
index 000000000000..8ea881fba09c
--- /dev/null
+++ b/core/java/android/app/IWindowToken.aidl
@@ -0,0 +1,33 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+package android.app;
+
+import android.content.res.Configuration;
+import android.view.IWindow;
+
+/**
+ * Callback to receive configuration changes from {@link com.android.server.WindowToken}.
+ * WindowToken can be regarded to as a group of {@link android.view.IWindow} added from the same
+ * visual context, such as {@link Activity} or one created with
+ * {@link android.content.Context#createWindowContext(int)}. When WindowToken receives configuration
+ * changes and/or when it is moved between displays, it will propagate the changes to client side
+ * via this interface.
+ * @see android.content.Context#createWindowContext(int)
+ * {@hide}
+ */
+oneway interface IWindowToken {
+ void onConfigurationChanged(in Configuration newConfig, int newDisplayId);
+}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 4b0cadbd9c65..2122e92ba5b5 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
import android.app.trust.ITrustManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -676,8 +677,9 @@ public class KeyguardManager {
/**
* Determine if a given password is valid based off its lock type and expected complexity level.
*
- * @param isPin - whether this is a PIN-type password (only digits)
- * @param password - password to validate
+ * @param lockType - type of lock as specified in {@link LockTypes}
+ * @param password - password to validate; this has the same encoding
+ * as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
* @return true if the password is valid, false otherwise
@@ -685,8 +687,8 @@ public class KeyguardManager {
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@SystemApi
- public boolean validateLockPasswordComplexity(
- boolean isPin, @NonNull byte[] password, int complexity) {
+ public boolean isValidLockPasswordComplexity(@LockTypes int lockType, @NonNull byte[] password,
+ @PasswordComplexity int complexity) {
if (!checkInitialLockMethodUsage()) {
return false;
}
@@ -696,9 +698,11 @@ public class KeyguardManager {
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
PasswordMetrics adminMetrics =
devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
+ // Check if the password fits the mold of a pin or pattern.
+ boolean isPinOrPattern = lockType != LockTypes.PASSWORD;
return PasswordMetrics.validatePassword(
- adminMetrics, complexity, isPin, password).size() == 0;
+ adminMetrics, complexity, isPinOrPattern, password).size() == 0;
}
/**
@@ -712,7 +716,7 @@ public class KeyguardManager {
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@SystemApi
- public int getMinLockLength(boolean isPin, int complexity) {
+ public int getMinLockLength(boolean isPin, @PasswordComplexity int complexity) {
if (!checkInitialLockMethodUsage()) {
return -1;
}
@@ -731,7 +735,8 @@ public class KeyguardManager {
* Set the lockscreen password after validating against its expected complexity level.
*
* @param lockType - type of lock as specified in {@link LockTypes}
- * @param password - password to validate
+ * @param password - password to validate; this has the same encoding
+ * as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
* @return true if the lock is successfully set, false otherwise
@@ -739,7 +744,8 @@ public class KeyguardManager {
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@SystemApi
- public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, int complexity) {
+ public boolean setLock(@LockTypes int lockType, @NonNull byte[] password,
+ @PasswordComplexity int complexity) {
if (!checkInitialLockMethodUsage()) {
return false;
}
@@ -750,7 +756,7 @@ public class KeyguardManager {
Log.e(TAG, "Password already set, rejecting call to setLock");
return false;
}
- if (!validateLockPasswordComplexity(lockType != LockTypes.PASSWORD, password, complexity)) {
+ if (!isValidLockPasswordComplexity(lockType, password, complexity)) {
Log.e(TAG, "Password is not valid, rejecting call to setLock");
return false;
}
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index d279983a5793..568456270809 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -15,10 +15,12 @@
*/
package android.app;
+import static android.view.WindowManagerGlobal.ADD_OKAY;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.ContextWrapper;
-import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -26,73 +28,62 @@ import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;
+import java.lang.ref.Reference;
+
/**
* {@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}.
+ * used when a new window is added via {@link android.view.WindowManager#addView}.
*
* @see Context#createWindowContext(int, Bundle)
* @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 final WindowTokenClient mToken;
private boolean mOwnsToken;
/**
- * Default constructor. Can either accept an existing token or generate one and registers it
- * with the server if necessary.
+ * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
+ * the token.
*
* @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, Bundle options) {
+ public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
+ // Correct base context will be built once the token is resolved, so passing 'null' here.
super(null /* base */);
mWms = WindowManagerGlobal.getWindowManagerService();
- if (token != null && !isWindowToken(token)) {
- throw new IllegalArgumentException("Token must be registered to server.");
- }
- mToken = token != null ? token : new Binder();
+ mToken = new WindowTokenClient();
+
final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
attachBaseContext(contextImpl);
contextImpl.setOuterContext(this);
- mDisplayId = getDisplayId();
+ mToken.attachContext(this);
+
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;
- }
+ int result;
try {
- mWms.addWindowTokenWithOptions(mToken, type, mDisplayId, options, getPackageName());
+ // Register the token with WindowManager. This will also call back with the current
+ // config back to the client.
+ result = mWms.addWindowTokenWithOptions(
+ mToken, type, getDisplayId(), options, 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;
+ mOwnsToken = result == ADD_OKAY;
+ Reference.reachabilityFence(this);
}
private static ContextImpl createBaseWindowContext(Context outer, IBinder token) {
@@ -112,7 +103,7 @@ public class WindowContext extends ContextWrapper {
protected void finalize() throws Throwable {
if (mOwnsToken) {
try {
- mWms.removeWindowToken(mToken, mDisplayId);
+ mWms.removeWindowToken(mToken, getDisplayId());
mOwnsToken = false;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java
new file mode 100644
index 000000000000..ed0179bb9839
--- /dev/null
+++ b/core/java/android/app/WindowTokenClient.java
@@ -0,0 +1,76 @@
+/*
+ * 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.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * Client implementation of {@link IWindowToken}. It can receive configuration change callbacks from
+ * server when window token config is updated or when it is moved between displays, and update the
+ * resources associated with this token on the client side. This will make sure that
+ * {@link WindowContext} instances will have updated resources and configuration.
+ * @hide
+ */
+public class WindowTokenClient extends IWindowToken.Stub {
+ /**
+ * Attached {@link Context} for this window token to update configuration and resources.
+ * Initialized by {@link #attachContext(Context)}.
+ */
+ private Context mContext = null;
+
+ private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
+
+ /**
+ * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
+ * can only attach one {@link Context}.
+ * <p>This method must be called before invoking
+ * {@link android.view.IWindowManager#addWindowTokenWithOptions(IBinder, int, int, Bundle,
+ * String)}.<p/>
+ *
+ * @param context context to be attached
+ * @throws IllegalStateException if attached context has already existed.
+ */
+ void attachContext(@NonNull Context context) {
+ if (mContext != null) {
+ throw new IllegalStateException("Context is already attached.");
+ }
+ mContext = context;
+ ContextImpl impl = ContextImpl.getImpl(mContext);
+ impl.setResources(impl.createWindowContextResources());
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
+ final int currentDisplayId = mContext.getDisplayId();
+ final boolean displayChanged = newDisplayId != currentDisplayId;
+ final Configuration config = new Configuration(mContext.getResources()
+ .getConfiguration());
+ final boolean configChanged = config.isOtherSeqNewer(newConfig)
+ && config.updateFrom(newConfig) != 0;
+ if (displayChanged || configChanged) {
+ // TODO(ag/9789103): update resource manager logic to track non-activity tokens
+ mResourcesManager.updateResourcesForActivity(asBinder(), config, newDisplayId,
+ displayChanged);
+ }
+ if (displayChanged) {
+ mContext.updateDisplay(newDisplayId);
+ }
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 546fef913192..b219394ddfa9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8989,49 +8989,6 @@ public class DevicePolicyManager {
}
/**
- * Called by device owners to request a location provider to change its allowed state. For a
- * provider to be enabled requires both that the master location setting is enabled, and that
- * the provider itself is allowed. Most location providers are always allowed. Some location
- * providers may have user consents or terms and conditions that must be accepted, or some other
- * type of blocker before they are allowed however. Every location provider is responsible for
- * its own allowed state.
- *
- * <p>This method requests that a location provider change its allowed state. For providers that
- * are always allowed and have no state to change, this will have no effect. If the provider
- * does require some consent, terms and conditions, or other blocking state, using this API
- * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions,
- * etc, and the provider should make a best effort to adjust it's allowed state accordingly.
- *
- * <p>Location providers are generally only responsible for the current user, and callers must
- * assume that this method will only affect provider state for the current user. Callers are
- * responsible for tracking current user changes and re-updating provider state as necessary.
- *
- * <p>While providers are expected to make a best effort to honor this request, it is not a
- * given that all providers will support such a request. If a provider does change its state as
- * a result of this request, that may happen asynchronously after some delay. Test location
- * providers set through {@link android.location.LocationManager#addTestProvider} will respond
- * to this request to aide in testing.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with
- * @param provider A location provider as listed by
- * {@link android.location.LocationManager#getAllProviders()}
- * @param providerAllowed Whether the location provider is being requested to enable or disable
- * itself
- * @throws SecurityException if {@code admin} is not a device owner.
- */
- public void requestSetLocationProviderAllowed(@NonNull ComponentName admin,
- @NonNull String provider, boolean providerAllowed) {
- throwIfParentInstance("requestSetLocationProviderAllowed");
- if (mService != null) {
- try {
- mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
-
- /**
* Called by profile or device owners to update {@link android.provider.Settings.Secure}
* settings. Validation that the value of the setting is in the correct form for the setting
* type should be performed by the caller.
@@ -9975,20 +9932,27 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to control the security logging feature.
+ * Called by device owner or a profile owner of an organization-owned managed profile to
+ * control the security logging feature.
*
* <p> Security logs contain various information intended for security auditing purposes.
- * See {@link SecurityEvent} for details.
+ * When security logging is enabled by a profile owner of
+ * an organization-owned managed profile, certain security logs are not visible (for example
+ * personal app launch events) or they will be redacted (for example, details of the physical
+ * volume mount events). Please see {@link SecurityEvent} for details.
*
* <p><strong>Note:</strong> The device owner won't be able to retrieve security logs if there
* are unaffiliated secondary users or profiles on the device, regardless of whether the
* feature is enabled. Logs will be discarded if the internal buffer fills up while waiting for
* all users to become affiliated. Therefore it's recommended that affiliation ids are set for
- * new users as soon as possible after provisioning via {@link #setAffiliationIds}.
+ * new users as soon as possible after provisioning via {@link #setAffiliationIds}. Profile
+ * owner of organization-owned managed profile is not subject to this restriction since all
+ * privacy-sensitive events happening outside the managed profile would have been redacted
+ * already.
*
- * @param admin Which device owner this request is associated with.
+ * @param admin Which device admin this request is associated with.
* @param enabled whether security logging should be enabled or not.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not allowed to control security logging.
* @see #setAffiliationIds
* @see #retrieveSecurityLogs
*/
@@ -10002,14 +9966,14 @@ public class DevicePolicyManager {
}
/**
- * Return whether security logging is enabled or not by the device owner.
+ * Return whether security logging is enabled or not by the admin.
*
- * <p>Can only be called by the device owner, otherwise a {@link SecurityException} will be
- * thrown.
+ * <p>Can only be called by the device owner or a profile owner of an organization-owned
+ * managed profile, otherwise a {@link SecurityException} will be thrown.
*
- * @param admin Which device owner this request is associated with.
+ * @param admin Which device admin this request is associated with.
* @return {@code true} if security logging is enabled by device owner, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not allowed to control security logging.
*/
public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) {
throwIfParentInstance("isSecurityLoggingEnabled");
@@ -10021,20 +9985,21 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to retrieve all new security logging entries since the last call to
- * this API after device boots.
+ * Called by device owner or profile owner of an organization-owned managed profile to retrieve
+ * all new security logging entries since the last call to this API after device boots.
*
* <p> Access to the logs is rate limited and it will only return new logs after the device
* owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
*
- * <p>If there is any other user or profile on the device, it must be affiliated with the
- * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
+ * <p> When called by a device owner, if there is any other user or profile on the device,
+ * it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
+ * See {@link #isAffiliatedUser}.
*
- * @param admin Which device owner this request is associated with.
+ * @param admin Which device admin this request is associated with.
* @return the new batch of security logs which is a list of {@link SecurityEvent},
* or {@code null} if rate limitation is exceeded or if logging is currently disabled.
- * @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device.
+ * @throws SecurityException if {@code admin} is not allowed to access security logging,
+ * or there is at least one profile or secondary user that is not affiliated with the device.
* @see #isAffiliatedUser
* @see DeviceAdminReceiver#onSecurityLogsAvailable
*/
@@ -10167,21 +10132,23 @@ public class DevicePolicyManager {
}
/**
- * Called by device owners to retrieve device logs from before the device's last reboot.
+ * Called by device owner or profile owner of an organization-owned managed profile to retrieve
+ * device logs from before the device's last reboot.
* <p>
* <strong> This API is not supported on all devices. Calling this API on unsupported devices
* will result in {@code null} being returned. The device logs are retrieved from a RAM region
* which is not guaranteed to be corruption-free during power cycles, as a result be cautious
* about data corruption when parsing. </strong>
*
- * <p>If there is any other user or profile on the device, it must be affiliated with the
- * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}.
+ * <p> When called by a device owner, if there is any other user or profile on the device,
+ * it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
+ * See {@link #isAffiliatedUser}.
*
- * @param admin Which device owner this request is associated with.
+ * @param admin Which device admin this request is associated with.
* @return Device logs from before the latest reboot of the system, or {@code null} if this API
* is not supported on the device.
- * @throws SecurityException if {@code admin} is not a device owner, or there is at least one
- * profile or secondary user that is not affiliated with the device.
+ * @throws SecurityException if {@code admin} is not allowed to access security logging, or
+ * there is at least one profile or secondary user that is not affiliated with the device.
* @see #isAffiliatedUser
* @see #retrieveSecurityLogs
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d161e06d354d..da48663145e1 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -272,7 +272,6 @@ interface IDevicePolicyManager {
boolean hasLockdownAdminConfiguredNetworks(in ComponentName who);
void setLocationEnabled(in ComponentName who, boolean locationEnabled);
- void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed);
boolean setTime(in ComponentName who, long millis);
boolean setTimeZone(in ComponentName who, String timeZone);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 91cf120032b5..fb7f573d5535 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -23,11 +23,13 @@ import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.util.EventLog.Event;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
@@ -104,7 +106,8 @@ public class SecurityLog {
/**
* Indicates that a shell command was issued over ADB via {@code adb shell <command>}
* The log entry contains a {@code String} payload containing the shell command, accessible
- * via {@link SecurityEvent#getData()}.
+ * via {@link SecurityEvent#getData()}. If security logging is enabled on organization-owned
+ * managed profile devices, the shell command will be redacted to an empty string.
*/
public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
@@ -133,6 +136,8 @@ public class SecurityLog {
* <li> [3] app pid ({@code Integer})
* <li> [4] seinfo tag ({@code String})
* <li> [5] SHA-256 hash of the base APK in hexadecimal ({@code String})
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
@@ -205,7 +210,8 @@ public class SecurityLog {
* following information about the event, encapsulated in an {@link Object} array and
* accessible via {@link SecurityEvent#getData()}:
* <li> [0] mount point ({@code String})
- * <li> [1] volume label ({@code String}).
+ * <li> [1] volume label ({@code String}). Redacted to empty string on organization-owned
+ * managed profile devices.
*/
public static final int TAG_MEDIA_MOUNT = SecurityLogTags.SECURITY_MEDIA_MOUNTED;
@@ -214,7 +220,8 @@ public class SecurityLog {
* following information about the event, encapsulated in an {@link Object} array and
* accessible via {@link SecurityEvent#getData()}:
* <li> [0] mount point ({@code String})
- * <li> [1] volume label ({@code String}).
+ * <li> [1] volume label ({@code String}). Redacted to empty string on organization-owned
+ * managed profile devices.
*/
public static final int TAG_MEDIA_UNMOUNT = SecurityLogTags.SECURITY_MEDIA_UNMOUNTED;
@@ -340,6 +347,9 @@ public class SecurityLog {
* <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
* <li> [1] alias of the key ({@code String})
* <li> [2] requesting process uid ({@code Integer}).
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_KEY_GENERATED =
SecurityLogTags.SECURITY_KEY_GENERATED;
@@ -351,6 +361,9 @@ public class SecurityLog {
* <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
* <li> [1] alias of the key ({@code String})
* <li> [2] requesting process uid ({@code Integer}).
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_KEY_IMPORT = SecurityLogTags.SECURITY_KEY_IMPORTED;
@@ -361,6 +374,9 @@ public class SecurityLog {
* <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
* <li> [1] alias of the key ({@code String})
* <li> [2] requesting process uid ({@code Integer}).
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_KEY_DESTRUCTION = SecurityLogTags.SECURITY_KEY_DESTROYED;
@@ -370,6 +386,11 @@ public class SecurityLog {
* {@link Object} array and accessible via {@link SecurityEvent#getData()}:
* <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
* <li> [1] subject of the certificate ({@code String}).
+ * <li> [2] which user the certificate is installed for ({@code Integer}), only available from
+ * version {@link android.os.Build.VERSION_CODES#R}.
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_CERT_AUTHORITY_INSTALLED =
SecurityLogTags.SECURITY_CERT_AUTHORITY_INSTALLED;
@@ -380,6 +401,11 @@ public class SecurityLog {
* {@link Object} array and accessible via {@link SecurityEvent#getData()}:
* <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
* <li> [1] subject of the certificate ({@code String}).
+ * <li> [2] which user the certificate is removed from ({@code Integer}), only available from
+ * version {@link android.os.Build.VERSION_CODES#R}.
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_CERT_AUTHORITY_REMOVED =
SecurityLogTags.SECURITY_CERT_AUTHORITY_REMOVED;
@@ -422,6 +448,9 @@ public class SecurityLog {
* {@link SecurityEvent#getData()}:
* <li> [0] alias of the key ({@code String})
* <li> [1] owner application uid ({@code Integer}).
+ *
+ * If security logging is enabled on organization-owned managed profile devices, only events
+ * happening inside the managed profile will be visible.
*/
public static final int TAG_KEY_INTEGRITY_VIOLATION =
SecurityLogTags.SECURITY_KEY_INTEGRITY_VIOLATION;
@@ -535,6 +564,16 @@ public class SecurityLog {
return mEvent.getData();
}
+ /** @hide */
+ public int getIntegerData(int index) {
+ return (Integer) ((Object[]) mEvent.getData())[index];
+ }
+
+ /** @hide */
+ public String getStringData(int index) {
+ return (String) ((Object[]) mEvent.getData())[index];
+ }
+
/**
* @hide
*/
@@ -554,7 +593,7 @@ public class SecurityLog {
* Returns severity level for the event.
*/
public @SecurityLogLevel int getLogLevel() {
- switch (mEvent.getTag()) {
+ switch (getTag()) {
case TAG_ADB_SHELL_INTERACTIVE:
case TAG_ADB_SHELL_CMD:
case TAG_SYNC_RECV_FILE:
@@ -608,6 +647,75 @@ public class SecurityLog {
return array.length >= 1 && array[0] instanceof Integer && (Integer) array[0] != 0;
}
+ /**
+ * Returns a copy of the security event suitable to be consumed by the provided user.
+ * This method will either return the original event itself if the event does not contain
+ * any sensitive data; or a copy of itself but with sensitive information redacted; or
+ * {@code null} if the entire event should not be accessed by the given user.
+ *
+ * @param accessingUser which user this security event is to be accessed, must be a
+ * concrete user id.
+ * @hide
+ */
+ public SecurityEvent redact(int accessingUser) {
+ // Which user the event is associated with, for the purpose of log redaction.
+ final int userId;
+ switch (getTag()) {
+ case SecurityLog.TAG_ADB_SHELL_CMD:
+ return new SecurityEvent(getId(), mEvent.withNewData("").getBytes());
+ case SecurityLog.TAG_MEDIA_MOUNT:
+ case SecurityLog.TAG_MEDIA_UNMOUNT:
+ // Partial redaction
+ String mountPoint;
+ try {
+ mountPoint = getStringData(0);
+ } catch (Exception e) {
+ return null;
+ }
+ return new SecurityEvent(getId(),
+ mEvent.withNewData(new Object[] {mountPoint, ""}).getBytes());
+ case SecurityLog.TAG_APP_PROCESS_START:
+ try {
+ userId = UserHandle.getUserId(getIntegerData(2));
+ } catch (Exception e) {
+ return null;
+ }
+ break;
+ case SecurityLog.TAG_CERT_AUTHORITY_INSTALLED:
+ case SecurityLog.TAG_CERT_AUTHORITY_REMOVED:
+ try {
+ userId = getIntegerData(2);
+ } catch (Exception e) {
+ return null;
+ }
+ break;
+ case SecurityLog.TAG_KEY_GENERATED:
+ case SecurityLog.TAG_KEY_IMPORT:
+ case SecurityLog.TAG_KEY_DESTRUCTION:
+ try {
+ userId = UserHandle.getUserId(getIntegerData(2));
+ } catch (Exception e) {
+ return null;
+ }
+ break;
+ case SecurityLog.TAG_KEY_INTEGRITY_VIOLATION:
+ try {
+ userId = UserHandle.getUserId(getIntegerData(1));
+ } catch (Exception e) {
+ return null;
+ }
+ break;
+ default:
+ userId = UserHandle.USER_NULL;
+ }
+ // If the event is not user-specific, or matches the accessing user, return it
+ // unmodified, else redact by returning null
+ if (userId == UserHandle.USER_NULL || accessingUser == userId) {
+ return this;
+ } else {
+ return null;
+ }
+ }
@Override
public int describeContents() {
@@ -657,6 +765,30 @@ public class SecurityLog {
return other != null && mEvent.equals(other.mEvent);
}
}
+
+ /**
+ * Redacts events in-place according to which user will consume the events.
+ *
+ * @param accessingUser which user will consume the redacted events, or UserHandle.USER_ALL if
+ * redaction should be skipped.
+ * @hide
+ */
+ public static void redactEvents(ArrayList<SecurityEvent> logList, int accessingUser) {
+ if (accessingUser == UserHandle.USER_ALL) return;
+ int end = 0;
+ for (int i = 0; i < logList.size(); i++) {
+ SecurityEvent event = logList.get(i);
+ event = event.redact(accessingUser);
+ if (event != null) {
+ logList.set(end, event);
+ end++;
+ }
+ }
+ for (int i = logList.size() - 1; i >= end; i--) {
+ logList.remove(i);
+ }
+ }
+
/**
* Retrieve all security logs and return immediately.
* @hide
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 4e67fe253715..100fd4cbd40f 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -33,8 +33,8 @@ option java_package android.app.admin
210026 security_key_destroyed (success|1),(key_id|3),(uid|1)
210027 security_user_restriction_added (package|3),(admin_user|1),(restriction|3)
210028 security_user_restriction_removed (package|3),(admin_user|1),(restriction|3)
-210029 security_cert_authority_installed (success|1),(subject|3)
-210030 security_cert_authority_removed (success|1),(subject|3)
+210029 security_cert_authority_installed (success|1),(subject|3),(target_user|1)
+210030 security_cert_authority_removed (success|1),(subject|3),(target_user|1)
210031 security_crypto_self_test_completed (success|1)
210032 security_key_integrity_violation (key_id|3),(uid|1)
210033 security_cert_validation_failure (reason|3)
diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl
index 36c71bff7682..6d543963fe2a 100644
--- a/core/java/android/app/trust/IStrongAuthTracker.aidl
+++ b/core/java/android/app/trust/IStrongAuthTracker.aidl
@@ -23,4 +23,5 @@ package android.app.trust;
*/
oneway interface IStrongAuthTracker {
void onStrongAuthRequiredChanged(int strongAuthRequired, int userId);
+ void onIsNonStrongBiometricAllowedChanged(boolean allowed, int userId);
} \ No newline at end of file
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index e1942da8ac7f..bd3298c79fff 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -580,6 +580,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
@Override
+ public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ RemoteCallback callback) {
+ final Bundle result = new Bundle();
+ result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+ canonicalize(callingPkg, featureId, uri));
+ callback.sendResult(result);
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, String featureId, Uri uri) {
uri = validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 0f1442d864ba..7bc59013bcfe 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -359,6 +359,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return true;
}
+ case CANONICALIZE_ASYNC_TRANSACTION: {
+ data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
+ String featureId = data.readString();
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data);
+ canonicalizeAsync(callingPkg, featureId, uri, callback);
+ return true;
+ }
+
case UNCANONICALIZE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -823,6 +833,25 @@ final class ContentProviderProxy implements IContentProvider
}
@Override
+ /* oneway */ public void canonicalizeAsync(String callingPkg, @Nullable String featureId,
+ Uri uri, RemoteCallback callback) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ data.writeString(callingPkg);
+ data.writeString(featureId);
+ uri.writeToParcel(data, 0);
+ callback.writeToParcel(data, 0);
+
+ mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null,
+ Binder.FLAG_ONEWAY);
+ } finally {
+ data.recycle();
+ }
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0e0161ff4e9f..b748cfa775ed 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -712,14 +712,17 @@ public abstract class ContentResolver implements ContentInterface {
* {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}.
* @hide
*/
- public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS =
+ public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS =
CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;
+ // Timeout given a ContentProvider that has already been started and connected to.
+ private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000;
+
// Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
// long ActivityManagerService is giving a content provider to get published if a new process
// needs to be started for that.
- private static final int GET_TYPE_TIMEOUT_MILLIS =
- CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000;
+ private static final int REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS =
+ CONTENT_PROVIDER_READY_TIMEOUT_MILLIS + CONTENT_PROVIDER_TIMEOUT_MILLIS;
public ContentResolver(@Nullable Context context) {
this(context, null);
@@ -833,10 +836,10 @@ public abstract class ContentResolver implements ContentInterface {
IContentProvider provider = acquireExistingProvider(url);
if (provider != null) {
try {
- final GetTypeResultListener resultListener = new GetTypeResultListener();
+ final StringResultListener resultListener = new StringResultListener();
provider.getTypeAsync(url, new RemoteCallback(resultListener));
- resultListener.waitForResult();
- return resultListener.type;
+ resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -854,13 +857,13 @@ public abstract class ContentResolver implements ContentInterface {
}
try {
- GetTypeResultListener resultListener = new GetTypeResultListener();
+ final StringResultListener resultListener = new StringResultListener();
ActivityManager.getService().getProviderMimeTypeAsync(
ContentProvider.getUriWithoutUserId(url),
resolveUserId(url),
new RemoteCallback(resultListener));
- resultListener.waitForResult();
- return resultListener.type;
+ resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// We just failed to send a oneway request to the System Server. Nothing to do.
return null;
@@ -870,27 +873,29 @@ public abstract class ContentResolver implements ContentInterface {
}
}
- private static class GetTypeResultListener implements RemoteCallback.OnResultListener {
+ private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener {
@GuardedBy("this")
public boolean done;
@GuardedBy("this")
- public String type;
+ public T result;
@Override
public void onResult(Bundle result) {
synchronized (this) {
- type = result.getString(REMOTE_CALLBACK_RESULT);
+ this.result = getResultFromBundle(result);
done = true;
notifyAll();
}
}
- public void waitForResult() {
+ protected abstract T getResultFromBundle(Bundle result);
+
+ public void waitForResult(long timeout) {
synchronized (this) {
if (!done) {
try {
- wait(GET_TYPE_TIMEOUT_MILLIS);
+ wait(timeout);
} catch (InterruptedException e) {
// Ignore
}
@@ -899,6 +904,20 @@ public abstract class ContentResolver implements ContentInterface {
}
}
+ private static class StringResultListener extends ResultListener<String> {
+ @Override
+ protected String getResultFromBundle(Bundle result) {
+ return result.getString(REMOTE_CALLBACK_RESULT);
+ }
+ }
+
+ private static class UriResultListener extends ResultListener<Uri> {
+ @Override
+ protected Uri getResultFromBundle(Bundle result) {
+ return result.getParcelable(REMOTE_CALLBACK_RESULT);
+ }
+ }
+
/**
* Query for the possible MIME types for the representations the given
* content URL can be returned when opened as as stream with
@@ -1192,7 +1211,11 @@ public abstract class ContentResolver implements ContentInterface {
}
try {
- return provider.canonicalize(mPackageName, mFeatureId, url);
+ final UriResultListener resultListener = new UriResultListener();
+ provider.canonicalizeAsync(mPackageName, mFeatureId, url,
+ new RemoteCallback(resultListener));
+ resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+ return resultListener.result;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 4658ba109d5f..37643da375df 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -45,7 +45,7 @@ public interface IContentProvider extends IInterface {
public String getType(Uri url) throws RemoteException;
/**
- * An oneway version of getType. The functionality is exactly the same, except that the
+ * A oneway version of getType. The functionality is exactly the same, except that the
* call returns immediately, and the resulting type is returned when available via
* a binder callback.
*/
@@ -126,6 +126,14 @@ public interface IContentProvider extends IInterface {
public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException;
+ /**
+ * A oneway version of canonicalize. The functionality is exactly the same, except that the
+ * call returns immediately, and the resulting type is returned when available via
+ * a binder callback.
+ */
+ void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ RemoteCallback callback) throws RemoteException;
+
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException;
@@ -162,4 +170,5 @@ public interface IContentProvider extends IInterface {
static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27;
int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28;
+ int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29;
}
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index b5f4f806d244..8a89840876d9 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -95,9 +95,9 @@ interface ILauncherApps {
void registerShortcutChangeCallback(String callingPackage, long changedSince,
String packageName, in List shortcutIds, in List<LocusId> locusIds,
- in ComponentName componentName, int flags, in IShortcutChangeCallback callback,
- int callbackId);
- void unregisterShortcutChangeCallback(String callingPackage, int callbackId);
+ in ComponentName componentName, int flags, in IShortcutChangeCallback callback);
+ void unregisterShortcutChangeCallback(String callingPackage,
+ in IShortcutChangeCallback callback);
void cacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5aa0208480c1..86242fd6f82f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -17,6 +17,7 @@
package android.content.pm;
import static android.Manifest.permission;
+
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -161,7 +162,7 @@ public class LauncherApps {
private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
- private final Map<Integer, Pair<Executor, ShortcutChangeCallback>>
+ private final Map<ShortcutChangeCallback, Pair<Executor, IShortcutChangeCallback>>
mShortcutChangeCallbacks = new HashMap<>();
/**
@@ -549,8 +550,8 @@ public class LauncherApps {
android.content.pm.IShortcutChangeCallback.Stub {
private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
- ShortcutChangeCallbackProxy(Pair<Executor, ShortcutChangeCallback> remoteReferences) {
- mRemoteReferences = new WeakReference<>(remoteReferences);
+ ShortcutChangeCallbackProxy(Executor executor, ShortcutChangeCallback callback) {
+ mRemoteReferences = new WeakReference<>(new Pair<>(executor, callback));
}
@Override
@@ -1753,14 +1754,12 @@ public class LauncherApps {
Objects.requireNonNull(executor, "Executor cannot be null");
synchronized (mShortcutChangeCallbacks) {
- final int callbackId = callback.hashCode();
- final Pair<Executor, ShortcutChangeCallback> state = new Pair<>(executor, callback);
- mShortcutChangeCallbacks.put(callbackId, state);
+ IShortcutChangeCallback proxy = new ShortcutChangeCallbackProxy(executor, callback);
+ mShortcutChangeCallbacks.put(callback, new Pair<>(executor, proxy));
try {
mService.registerShortcutChangeCallback(mContext.getPackageName(),
query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
- query.mActivity, query.mQueryFlags, new ShortcutChangeCallbackProxy(state),
- callbackId);
+ query.mActivity, query.mQueryFlags, proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1779,12 +1778,10 @@ public class LauncherApps {
Objects.requireNonNull(callback, "Callback cannot be null");
synchronized (mShortcutChangeCallbacks) {
- final int callbackId = callback.hashCode();
- if (mShortcutChangeCallbacks.containsKey(callbackId)) {
- mShortcutChangeCallbacks.remove(callbackId);
+ if (mShortcutChangeCallbacks.containsKey(callback)) {
+ IShortcutChangeCallback proxy = mShortcutChangeCallbacks.remove(callback).second;
try {
- mService.unregisterShortcutChangeCallback(mContext.getPackageName(),
- callbackId);
+ mService.unregisterShortcutChangeCallback(mContext.getPackageName(), proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3a934211c7e5..a50ce92a70bf 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -65,6 +65,9 @@ public abstract class ShortcutServiceInternal {
public abstract void addListener(@NonNull ShortcutChangeListener listener);
+ public abstract void addShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback);
+
public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 6ad7faed16d8..ce26cb0d7adc 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -28,21 +28,21 @@ import java.util.Objects;
* @hide
*/
public final class DeviceProductInfo implements Parcelable {
- final private String mName;
- final private String mManufacturerPnpId;
- final private String mProductId;
- final private Integer mModelYear;
- final private ManufactureDate mManufactureDate;
+ private final String mName;
+ private final String mManufacturerPnpId;
+ private final String mProductId;
+ private final Integer mModelYear;
+ private final ManufactureDate mManufactureDate;
public DeviceProductInfo(
String name,
String manufacturerPnpId,
- String productCode,
+ String productId,
Integer modelYear,
ManufactureDate manufactureDate) {
this.mName = name;
this.mManufacturerPnpId = manufacturerPnpId;
- this.mProductId = productCode;
+ this.mProductId = productId;
this.mModelYear = modelYear;
this.mManufactureDate = manufactureDate;
}
@@ -158,8 +158,8 @@ public final class DeviceProductInfo implements Parcelable {
* @hide
*/
public static class ManufactureDate implements Parcelable {
- final private Integer mWeek;
- final private Integer mYear;
+ private final Integer mWeek;
+ private final Integer mYear;
public ManufactureDate(Integer week, Integer year) {
mWeek = week;
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 3a0660db2b05..9b9889ed5cb2 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -97,8 +97,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
@Override // binder call
- public void onAuthenticationSucceeded(long deviceId, Face face, int userId) {
- mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, face).sendToTarget();
+ public void onAuthenticationSucceeded(long deviceId, Face face, int userId,
+ boolean isStrongBiometric) {
+ mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0,
+ face).sendToTarget();
}
@Override // binder call
@@ -814,6 +816,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
private Face mFace;
private CryptoObject mCryptoObject;
private int mUserId;
+ private boolean mIsStrongBiometric;
/**
* Authentication result
@@ -822,10 +825,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @param face the recognized face data, if allowed.
* @hide
*/
- public AuthenticationResult(CryptoObject crypto, Face face, int userId) {
+ public AuthenticationResult(CryptoObject crypto, Face face, int userId,
+ boolean isStrongBiometric) {
mCryptoObject = crypto;
mFace = face;
mUserId = userId;
+ mIsStrongBiometric = isStrongBiometric;
}
/**
@@ -857,6 +862,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
public int getUserId() {
return mUserId;
}
+
+ /**
+ * Check whether the strength of the face modality associated with this operation is strong
+ * (i.e. not weak or convenience).
+ *
+ * @hide
+ */
+ public boolean isStrongBiometric() {
+ return mIsStrongBiometric;
+ }
}
/**
@@ -1056,7 +1071,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
msg.arg2 /* vendorCode */);
break;
case MSG_AUTHENTICATION_SUCCEEDED:
- sendAuthenticatedSucceeded((Face) msg.obj, msg.arg1 /* userId */);
+ sendAuthenticatedSucceeded((Face) msg.obj, msg.arg1 /* userId */,
+ msg.arg2 == 1 /* isStrongBiometric */);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
@@ -1133,10 +1149,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
}
- private void sendAuthenticatedSucceeded(Face face, int userId) {
+ private void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) {
if (mAuthenticationCallback != null) {
final AuthenticationResult result =
- new AuthenticationResult(mCryptoObject, face, userId);
+ new AuthenticationResult(mCryptoObject, face, userId, isStrongBiometric);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 8ba24735c039..63182744eb0a 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -110,4 +110,7 @@ interface IFaceService {
void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName);
void userActivity();
+
+ // Initialize the OEM configured biometric strength
+ void initConfiguredStrength(int strength);
}
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index 10f9c435c415..7582308e8016 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -24,7 +24,8 @@ import android.hardware.face.Face;
oneway interface IFaceServiceReceiver {
void onEnrollResult(long deviceId, int faceId, int remaining);
void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
- void onAuthenticationSucceeded(long deviceId, in Face face, int userId);
+ void onAuthenticationSucceeded(long deviceId, in Face face, int userId,
+ boolean isStrongBiometric);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error, int vendorCode);
void onRemoved(long deviceId, int faceId, int remaining);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index f301a5cddc9c..dc8ea5efcc17 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -176,6 +176,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private Fingerprint mFingerprint;
private CryptoObject mCryptoObject;
private int mUserId;
+ private boolean mIsStrongBiometric;
/**
* Authentication result
@@ -184,10 +185,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @param fingerprint the recognized fingerprint data, if allowed.
* @hide
*/
- public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId) {
+ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint, int userId,
+ boolean isStrongBiometric) {
mCryptoObject = crypto;
mFingerprint = fingerprint;
mUserId = userId;
+ mIsStrongBiometric = isStrongBiometric;
}
/**
@@ -211,6 +214,15 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
public int getUserId() { return mUserId; }
+
+ /**
+ * Check whether the strength of the fingerprint modality associated with this operation is
+ * strong (i.e. not weak or convenience).
+ * @hide
+ */
+ public boolean isStrongBiometric() {
+ return mIsStrongBiometric;
+ }
};
/**
@@ -833,7 +845,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
msg.arg2 /* vendorCode */);
break;
case MSG_AUTHENTICATION_SUCCEEDED:
- sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
+ sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */,
+ msg.arg2 == 1 /* isStrongBiometric */);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
@@ -890,10 +903,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
- private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
+ private void sendAuthenticatedSucceeded(Fingerprint fp, int userId, boolean isStrongBiometric) {
if (mAuthenticationCallback != null) {
final AuthenticationResult result =
- new AuthenticationResult(mCryptoObject, fp, userId);
+ new AuthenticationResult(mCryptoObject, fp, userId, isStrongBiometric);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
@@ -1078,8 +1091,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
@Override // binder call
- public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
- mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
+ public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId,
+ boolean isStrongBiometric) {
+ mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0,
+ fp).sendToTarget();
}
@Override // binder call
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index f2ffd08d5bc8..028544854235 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -113,4 +113,7 @@ interface IFingerprintService {
// Removes a callback set by addClientActiveCallback
void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
+
+ // Initialize the OEM configured biometric strength
+ void initConfiguredStrength(int strength);
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index cf1c94ea5346..4412cee31bb0 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@ import android.hardware.fingerprint.Fingerprint;
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
- void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId);
+ void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId,
+ boolean isStrongBiometric);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error, int vendorCode);
void onRemoved(long deviceId, int fingerId, int groupId, int remaining);
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
index 8cf3c13b1465..5ef0a0c55a18 100644
--- a/core/java/android/hardware/iris/IIrisService.aidl
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -21,4 +21,6 @@ package android.hardware.iris;
* @hide
*/
interface IIrisService {
-} \ No newline at end of file
+ // Initialize the OEM configured biometric strength
+ void initConfiguredStrength(int strength);
+}
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index d207e7960d34..ae17378cfc4c 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -83,69 +84,10 @@ public final class NetworkScore implements Parcelable {
uplinkBandwidthKBps = uplinkBandwidth;
}
- /**
- * Evaluate whether a metrics codes for faster network is faster than another.
- *
- * This is a simple comparison of expected speeds. If either of the tested attributes
- * are unknown, this returns zero. This implementation just assumes downlink bandwidth
- * is more important than uplink bandwidth, which is more important than latency. This
- * is not a very good way of evaluating network speed, but it's a start.
- * TODO : do something more representative of how fast the network feels
- *
- * @param other the Metrics to evaluate against
- * @return a negative integer, zero, or a positive integer as this metrics is worse than,
- * equally good as (or unknown), or better than the passed Metrics.
- * @see #compareToPreferringKnown(Metrics)
- * @hide
- */
- // Can't implement Comparable<Metrics> because this is @hide.
- public int compareTo(@NonNull final Metrics other) {
- if (downlinkBandwidthKBps != BANDWIDTH_UNKNOWN
- && other.downlinkBandwidthKBps != BANDWIDTH_UNKNOWN) {
- if (downlinkBandwidthKBps > other.downlinkBandwidthKBps) return 1;
- if (downlinkBandwidthKBps < other.downlinkBandwidthKBps) return -1;
- }
- if (uplinkBandwidthKBps != BANDWIDTH_UNKNOWN
- && other.uplinkBandwidthKBps != BANDWIDTH_UNKNOWN) {
- if (uplinkBandwidthKBps > other.uplinkBandwidthKBps) return 1;
- if (uplinkBandwidthKBps < other.uplinkBandwidthKBps) return -1;
- }
- if (latencyMs != LATENCY_UNKNOWN && other.latencyMs != LATENCY_UNKNOWN) {
- // Latency : lower is better
- if (latencyMs > other.latencyMs) return -1;
- if (latencyMs < other.latencyMs) return 1;
- }
- return 0;
- }
-
- /**
- * Evaluate whether a metrics codes for faster network is faster than another.
- *
- * This is a simple comparison of expected speeds. If either of the tested attributes
- * are unknown, this prefers the known attributes. This implementation just assumes
- * downlink bandwidth is more important than uplink bandwidth, which is more important than
- * latency. This is not a very good way of evaluating network speed, but it's a start.
- * TODO : do something more representative of how fast the network feels
- *
- * @param other the Metrics to evaluate against
- * @return a negative integer, zero, or a positive integer as this metrics is worse than,
- * equally good as (or unknown), or better than the passed Metrics.
- * @see #compareTo(Metrics)
- * @hide
- */
- public int compareToPreferringKnown(@NonNull final Metrics other) {
- if (downlinkBandwidthKBps > other.downlinkBandwidthKBps) return 1;
- if (downlinkBandwidthKBps < other.downlinkBandwidthKBps) return -1;
- if (uplinkBandwidthKBps > other.uplinkBandwidthKBps) return 1;
- if (uplinkBandwidthKBps < other.uplinkBandwidthKBps) return -1;
- // Latency : lower is better
- return -Integer.compare(latencyMs, other.latencyMs);
- }
-
/** toString */
public String toString() {
return "latency = " + latencyMs + " downlinkBandwidth = " + downlinkBandwidthKBps
- + " uplinkBandwidth = " + uplinkBandwidthKBps;
+ + "uplinkBandwidth = " + uplinkBandwidthKBps;
}
@NonNull
@@ -405,33 +347,6 @@ public final class NetworkScore implements Parcelable {
return mLegacyScore;
}
- /**
- * Use the metrics to evaluate whether a network is faster than another.
- *
- * This is purely based on the metrics, and explicitly ignores policy or exiting. It's
- * provided to get a decision on two networks when policy can not decide, or to evaluate
- * how a network is expected to compare to another if it should validate.
- *
- * @param other the score to evaluate against
- * @return whether this network is probably faster than the other
- * @hide
- */
- public boolean probablyFasterThan(@NonNull final NetworkScore other) {
- if (mLegacyScore > other.mLegacyScore) return true;
- final int atEndToEnd = mEndToEndMetrics.compareTo(other.mEndToEndMetrics);
- if (atEndToEnd > 0) return true;
- if (atEndToEnd < 0) return false;
- final int atLinkLayer = mLinkLayerMetrics.compareTo(other.mLinkLayerMetrics);
- if (atLinkLayer > 0) return true;
- if (atLinkLayer < 0) return false;
- final int atEndToEndPreferringKnown =
- mEndToEndMetrics.compareToPreferringKnown(other.mEndToEndMetrics);
- if (atEndToEndPreferringKnown > 0) return true;
- if (atEndToEndPreferringKnown < 0) return false;
- // If this returns 0, neither is "probably faster" so just return false.
- return mLinkLayerMetrics.compareToPreferringKnown(other.mLinkLayerMetrics) > 0;
- }
-
/** Builder for NetworkScore. */
public static class Builder {
private int mPolicy = 0;
@@ -439,27 +354,17 @@ public final class NetworkScore implements Parcelable {
private Metrics mLinkLayerMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
@NonNull
- private Metrics mEndToEndMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+ private Metrics mEndToMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
private int mSignalStrength = UNKNOWN_SIGNAL_STRENGTH;
private int mRange = RANGE_UNKNOWN;
private boolean mExiting = false;
private int mLegacyScore = 0;
+ @NonNull private Bundle mExtensions = new Bundle();
/** Create a new builder. */
public Builder() { }
- /** @hide */
- public Builder(@NonNull final NetworkScore source) {
- mPolicy = source.mPolicy;
- mLinkLayerMetrics = source.mLinkLayerMetrics;
- mEndToEndMetrics = source.mEndToEndMetrics;
- mSignalStrength = source.mSignalStrength;
- mRange = source.mRange;
- mExiting = source.mExiting;
- mLegacyScore = source.mLegacyScore;
- }
-
/** Add a policy flag. */
@NonNull public Builder addPolicy(@Policy final int policy) {
mPolicy |= policy;
@@ -480,7 +385,7 @@ public final class NetworkScore implements Parcelable {
/** Set the end-to-end metrics. */
@NonNull public Builder setEndToEndMetrics(@NonNull final Metrics endToEndMetrics) {
- mEndToEndMetrics = endToEndMetrics;
+ mEndToMetrics = endToEndMetrics;
return this;
}
@@ -512,7 +417,7 @@ public final class NetworkScore implements Parcelable {
/** Build the NetworkScore object represented by this builder. */
@NonNull public NetworkScore build() {
- return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToMetrics,
mSignalStrength, mRange, mExiting, mLegacyScore);
}
}
diff --git a/core/java/android/os/CoolingDevice.aidl b/core/java/android/os/CoolingDevice.aidl
index 478e4bd71e6d..c6432fd31d20 100644
--- a/core/java/android/os/CoolingDevice.aidl
+++ b/core/java/android/os/CoolingDevice.aidl
@@ -16,4 +16,4 @@
package android.os;
-parcelable CoolingDevice;
+parcelable CoolingDevice cpp_header "android/CoolingDevice.h";
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index ad002335a010..c6c8adc4d8a9 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -56,7 +56,7 @@ interface IThermalService {
* @return list of {@link android.os.Temperature}.
* {@hide}
*/
- List<Temperature> getCurrentTemperatures();
+ Temperature[] getCurrentTemperatures();
/**
* Get current temperature with its throttling status on given temperature type.
@@ -64,7 +64,7 @@ interface IThermalService {
* @return list of {@link android.os.Temperature}.
* {@hide}
*/
- List<Temperature> getCurrentTemperaturesWithType(in int type);
+ Temperature[] getCurrentTemperaturesWithType(in int type);
/**
* Register a listener for thermal status change.
@@ -94,7 +94,7 @@ interface IThermalService {
* @return list of {@link android.os.CoolingDevice}.
* {@hide}
*/
- List<CoolingDevice> getCurrentCoolingDevices();
+ CoolingDevice[] getCurrentCoolingDevices();
/**
* Get current cooling devices on given type.
@@ -102,7 +102,8 @@ interface IThermalService {
* @return list of {@link android.os.CoolingDevice}.
* {@hide}
*/
- List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type);
+
+ CoolingDevice[] getCurrentCoolingDevicesWithType(in int type);
/**
* @param forecastSeconds how many seconds ahead to forecast the provided headroom
diff --git a/core/java/android/os/Temperature.aidl b/core/java/android/os/Temperature.aidl
index 708c08fbe8b0..5268dd5441e3 100644
--- a/core/java/android/os/Temperature.aidl
+++ b/core/java/android/os/Temperature.aidl
@@ -16,4 +16,4 @@
package android.os;
-parcelable Temperature;
+parcelable Temperature cpp_header "android/Temperature.h";
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 84fd58063d39..0f2060a36ac9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -63,6 +63,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* Manages users and user details on a multi-user system. There are two major categories of
@@ -2717,10 +2718,11 @@ public class UserManager {
Manifest.permission.CREATE_USERS})
@UserHandleAware
public @Nullable UserHandle createProfile(@NonNull String name, @NonNull String userType,
- @Nullable String[] disallowedPackages) throws UserOperationException {
+ @NonNull Set<String> disallowedPackages) throws UserOperationException {
try {
return mService.createProfileForUserWithThrow(name, userType, 0,
- mUserId, disallowedPackages).getUserHandle();
+ mUserId, disallowedPackages.toArray(
+ new String[disallowedPackages.size()])).getUserHandle();
} catch (ServiceSpecificException e) {
return returnNullOrThrowUserOperationException(e,
mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R);
@@ -3354,19 +3356,46 @@ public class UserManager {
}
/**
- * Returns a list of ids for profiles associated with the context user including the user
- * itself.
+ * Returns a list of ids for enabled profiles associated with the context user including the
+ * user itself.
*
- * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles
* @return A non-empty list of UserHandles associated with the calling user.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS}, conditional = true)
+ @UserHandleAware
+ public @NonNull List<UserHandle> getEnabledProfiles() {
+ return getProfiles(true);
+ }
+
+ /**
+ * Returns a list of ids for all profiles associated with the context user including the user
+ * itself.
*
+ * @return A non-empty list of UserHandles associated with the calling user.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS}, conditional = true)
@UserHandleAware
- public @NonNull List<UserHandle> getUserProfiles(boolean enabledOnly) {
+ public @NonNull List<UserHandle> getAllProfiles() {
+ return getProfiles(false);
+ }
+
+ /**
+ * Returns a list of ids for profiles associated with the context user including the user
+ * itself.
+ *
+ * @param enabledOnly whether to return only {@link UserInfo#isEnabled() enabled} profiles
+ * @return A non-empty list of UserHandles associated with the calling user.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS}, conditional = true)
+ @UserHandleAware
+ private @NonNull List<UserHandle> getProfiles(boolean enabledOnly) {
final int[] userIds = getProfileIds(mUserId, enabledOnly);
final List<UserHandle> result = new ArrayList<>(userIds.length);
for (int userId : userIds) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b9abdf83e260..b89827140da5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9275,11 +9275,17 @@ public final class Settings {
public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user";
/**
- * Whether ADB is enabled.
+ * Whether ADB over USB is enabled.
*/
public static final String ADB_ENABLED = "adb_enabled";
/**
+ * Whether ADB over Wifi is enabled.
+ * @hide
+ */
+ public static final String ADB_WIFI_ENABLED = "adb_wifi_enabled";
+
+ /**
* Whether Views are allowed to save their attribute data.
* @hide
*/
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index cb20db90f549..b23d0cd4bd93 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -15,11 +15,14 @@
*/
package android.service.controls;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +54,20 @@ public abstract class ControlsProviderService extends Service {
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_CONTROLS =
"android.service.controls.ControlsProviderService";
+
+ /**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ADD_CONTROL =
+ "android.service.controls.action.ADD_CONTROL";
+
+ /**
+ * @hide
+ */
+ public static final String EXTRA_CONTROL =
+ "android.service.controls.extra.CONTROL";
+
/**
* @hide
*/
@@ -325,6 +342,33 @@ public abstract class ControlsProviderService extends Service {
}
}
+ /**
+ * Request SystemUI to prompt the user to add a control to favorites.
+ *
+ * @param context A context
+ * @param componentName Component name of the {@link ControlsProviderService}
+ * @param control A stateless control to show to the user
+ */
+ public static void requestAddControl(@NonNull Context context,
+ @NonNull ComponentName componentName,
+ @NonNull Control control) {
+ Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(componentName);
+ Preconditions.checkNotNull(control);
+ final ComponentName sysuiComponent = ComponentName.unflattenFromString(
+ context.getResources().getString(
+ com.android.internal.R.string.config_systemUIServiceComponent));
+ Intent intent = new Intent(ACTION_ADD_CONTROL);
+ intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName);
+ intent.setPackage(sysuiComponent.getPackageName());
+ if (isStatelessControl(control)) {
+ intent.putExtra(EXTRA_CONTROL, control);
+ } else {
+ intent.putExtra(EXTRA_CONTROL, new Control.StatelessBuilder(control).build());
+ }
+ context.sendBroadcast(intent, Manifest.permission.BIND_CONTROLS);
+ }
+
private static class SubscriptionAdapter extends IControlsSubscription.Stub {
final Subscription mSubscription;
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index c9dc05b5aeb5..ead4e46cd28b 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,6 +16,8 @@
package android.util;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -62,7 +64,7 @@ public class EventLog {
private Exception mLastWtf;
// Layout of event log entry received from Android logger.
- // see system/core/include/log/log.h
+ // see system/core/liblog/include/log/log_read.h
private static final int LENGTH_OFFSET = 0;
private static final int HEADER_SIZE_OFFSET = 2;
private static final int PROCESS_OFFSET = 4;
@@ -73,7 +75,7 @@ public class EventLog {
// Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
private static final int V1_PAYLOAD_START = 20;
- private static final int DATA_OFFSET = 4;
+ private static final int TAG_LENGTH = 4;
// Value types
private static final byte INT_TYPE = 0;
@@ -121,26 +123,26 @@ public class EventLog {
/** @return the type tag code of the entry */
public int getTag() {
- int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
- if (offset == 0) {
- offset = V1_PAYLOAD_START;
- }
- return mBuffer.getInt(offset);
+ return mBuffer.getInt(getHeaderSize());
}
+ private int getHeaderSize() {
+ int length = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (length != 0) {
+ return length;
+ }
+ return V1_PAYLOAD_START;
+ }
/** @return one of Integer, Long, Float, String, null, or Object[] of same. */
public synchronized Object getData() {
try {
- int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
- if (offset == 0) {
- offset = V1_PAYLOAD_START;
- }
+ int offset = getHeaderSize();
mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
- if ((offset + DATA_OFFSET) >= mBuffer.limit()) {
+ if ((offset + TAG_LENGTH) >= mBuffer.limit()) {
// no payload
return null;
}
- mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
+ mBuffer.position(offset + TAG_LENGTH); // Just after the tag.
return decodeObject();
} catch (IllegalArgumentException e) {
Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
@@ -153,6 +155,28 @@ public class EventLog {
}
}
+ /**
+ * Construct a new EventLog object from the current object, copying all log metadata
+ * but replacing the actual payload with the content provided.
+ * @hide
+ */
+ public Event withNewData(@Nullable Object object) {
+ byte[] payload = encodeObject(object);
+ if (payload.length > 65535 - TAG_LENGTH) {
+ throw new IllegalArgumentException("Payload too long");
+ }
+ int headerLength = getHeaderSize();
+ byte[] newBytes = new byte[headerLength + TAG_LENGTH + payload.length];
+ // Copy header (including the 4 bytes of tag integer at the beginning of payload)
+ System.arraycopy(mBuffer.array(), 0, newBytes, 0, headerLength + TAG_LENGTH);
+ // Fill in encoded objects
+ System.arraycopy(payload, 0, newBytes, headerLength + TAG_LENGTH, payload.length);
+ Event result = new Event(newBytes);
+ // Patch payload length in header
+ result.mBuffer.putShort(LENGTH_OFFSET, (short) (payload.length + TAG_LENGTH));
+ return result;
+ }
+
/** @return the loggable item at the current position in mBuffer. */
private Object decodeObject() {
byte type = mBuffer.get();
@@ -190,6 +214,66 @@ public class EventLog {
}
}
+ private static @NonNull byte[] encodeObject(@Nullable Object object) {
+ if (object == null) {
+ return new byte[0];
+ }
+ if (object instanceof Integer) {
+ return ByteBuffer.allocate(1 + 4)
+ .order(ByteOrder.nativeOrder())
+ .put(INT_TYPE)
+ .putInt((Integer) object)
+ .array();
+ } else if (object instanceof Long) {
+ return ByteBuffer.allocate(1 + 8)
+ .order(ByteOrder.nativeOrder())
+ .put(LONG_TYPE)
+ .putLong((Long) object)
+ .array();
+ } else if (object instanceof Float) {
+ return ByteBuffer.allocate(1 + 4)
+ .order(ByteOrder.nativeOrder())
+ .put(FLOAT_TYPE)
+ .putFloat((Float) object)
+ .array();
+ } else if (object instanceof String) {
+ String string = (String) object;
+ byte[] bytes;
+ try {
+ bytes = string.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ bytes = new byte[0];
+ }
+ return ByteBuffer.allocate(1 + 4 + bytes.length)
+ .order(ByteOrder.nativeOrder())
+ .put(STRING_TYPE)
+ .putInt(bytes.length)
+ .put(bytes)
+ .array();
+ } else if (object instanceof Object[]) {
+ Object[] objects = (Object[]) object;
+ if (objects.length > 255) {
+ throw new IllegalArgumentException("Object array too long");
+ }
+ byte[][] bytes = new byte[objects.length][];
+ int totalLength = 0;
+ for (int i = 0; i < objects.length; i++) {
+ bytes[i] = encodeObject(objects[i]);
+ totalLength += bytes[i].length;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(1 + 1 + totalLength)
+ .order(ByteOrder.nativeOrder())
+ .put(LIST_TYPE)
+ .put((byte) objects.length);
+ for (int i = 0; i < objects.length; i++) {
+ buffer.put(bytes[i]);
+ }
+ return buffer.array();
+ } else {
+ throw new IllegalArgumentException("Unknown object type " + object);
+ }
+ }
+
/** @hide */
public static Event fromBytes(byte[] data) {
return new Event(data);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c60f7141f287..4196b5512dac 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -45,9 +45,6 @@ public class FeatureFlagUtils {
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";
- /** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
/** @hide */
@@ -70,9 +67,6 @@ 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");
// Disabled by default until b/148278926 is resolved. This flags guards a feature
// introduced in R and will be removed in the next release (b/148367230).
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false");
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 204d2c8bc2ce..148b32744e30 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -31,6 +31,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -39,11 +40,14 @@ import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
@@ -2067,9 +2071,12 @@ public final class ViewRootImpl implements ViewParent,
}
final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
final int flags = params.flags;
+ final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
+ final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
+ && params.type <= LAST_APPLICATION_WINDOW;
final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
- || (flags & FLAG_FULLSCREEN) != 0;
+ || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
@@ -2231,9 +2238,7 @@ public final class ViewRootImpl implements ViewParent,
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
mApplyInsetsRequested = false;
WindowInsets insets = getWindowInsets(true /* forceConstruct */);
- final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
- == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
- if (!dispatchCutout) {
+ if (!shouldDispatchCutout()) {
// Window is either not laid out in cutout or the status bar inset takes care of
// clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
insets = insets.consumeDisplayCutout();
@@ -2242,6 +2247,13 @@ public final class ViewRootImpl implements ViewParent,
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ private boolean shouldDispatchCutout() {
+ return mWindowAttributes.layoutInDisplayCutoutMode
+ == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ || mWindowAttributes.layoutInDisplayCutoutMode
+ == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ }
+
private void updateVisibleInsets() {
Rect visibleInsets = mInsetsController.calculateVisibleInsets(mPendingVisibleInsets,
mWindowAttributes.softInputMode);
@@ -2434,8 +2446,6 @@ public final class ViewRootImpl implements ViewParent,
params = lp;
}
if (sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- adjustLayoutParamsForCompatibility(lp);
- controlInsetsForCompatibility(lp);
handleDispatchSystemUiVisibilityChanged(mCompatibleVisibilityInfo);
}
@@ -2530,6 +2540,8 @@ public final class ViewRootImpl implements ViewParent,
&& !PixelFormat.formatHasAlpha(params.format)) {
params.format = PixelFormat.TRANSLUCENT;
}
+ adjustLayoutParamsForCompatibility(params);
+ controlInsetsForCompatibility(params);
}
if (mFirst || windowShouldResize || insetsChanged ||
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e731323845d3..b0d0a14c4d41 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -458,7 +458,7 @@ public interface WindowManager extends ViewManager {
}
/**
- * Returns the largets {@link WindowMetrics} an app may expect in the current system state.
+ * Returns the largest {@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}
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 84fed9c5ee90..823901896bb2 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -24,10 +24,10 @@ import android.view.View;
import com.android.internal.widget.ViewPager;
/**
- * A {@link ViewPager} which wraps around its first child's height and has swiping disabled.
+ * A {@link ViewPager} which wraps around its first child's height.
* <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 and share sheet's tabbed view.
+ * <p>This class is used for the intent resolver's tabbed view.
*/
public class ResolverViewPager extends ViewPager {
@@ -70,14 +70,4 @@ public class ResolverViewPager 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/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index ffa347c168f6..72f16e4e4a82 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -186,13 +186,6 @@ public class OverlayConfig {
*/
@NonNull
public static OverlayConfig getZygoteInstance() {
- if (Process.myUid() != Process.ROOT_UID) {
- // Scan the overlays in the zygote process to generate configuration settings for
- // overlays on the system image. Do not cache this instance so OverlayConfig will not
- // be present in applications by default.
- throw new IllegalStateException("Can only be invoked in the root process");
- }
-
Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#getZygoteInstance");
try {
return new OverlayConfig(null /* rootDirectory */, OverlayScanner::new,
@@ -209,13 +202,12 @@ public class OverlayConfig {
*/
@NonNull
public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
- if (Process.myUid() != Process.SYSTEM_UID) {
- throw new IllegalStateException("Can only be invoked in the system process");
- }
-
Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#initializeSystemInstance");
- sInstance = new OverlayConfig(null, null, packageProvider);
- Trace.traceEnd(Trace.TRACE_TAG_RRO);
+ try {
+ sInstance = new OverlayConfig(null, null, packageProvider);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RRO);
+ }
return sInstance;
}
@@ -373,10 +365,6 @@ public class OverlayConfig {
*/
@NonNull
public String[] createImmutableFrameworkIdmapsInZygote() {
- if (Process.myUid() != Process.ROOT_UID) {
- throw new IllegalStateException("This method can only be called from the root process");
- }
-
final String targetPath = "/system/framework/framework-res.apk";
final ArrayList<String> idmapPaths = new ArrayList<>();
final ArrayList<IdmapInvocation> idmapInvocations =
diff --git a/core/java/com/android/internal/content/om/TEST_MAPPING b/core/java/com/android/internal/content/om/TEST_MAPPING
new file mode 100644
index 000000000000..4cb595b01681
--- /dev/null
+++ b/core/java/com/android/internal/content/om/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "com.android.internal.content."
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index da1b72f05a98..99b4b5fb7707 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -46,9 +46,10 @@ public class DecorContext extends ContextThemeWrapper {
private WeakReference<Context> mActivityContext;
+ // TODO(b/149928768): Non-activity context can be passed.
@VisibleForTesting
public DecorContext(Context context, Context activityContext) {
- super(context.createDisplayContext(activityContext.getDisplay()), null);
+ super(context.createDisplayContext(activityContext.getDisplayNoVerify()), null);
mActivityContext = new WeakReference<>(activityContext);
mActivityResources = activityContext.getResources();
}
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index 720f4feeaebe..3c9791791a68 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -16,16 +16,12 @@
package com.android.internal.util;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.RemoteException;
import android.util.ExceptionUtils;
-import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Predicate;
import java.util.function.Supplier;
/**
@@ -222,20 +218,4 @@ public class FunctionalUtils {
}
}
}
-
- /**
- * Find the first element in the list that matches the predicate.
- *
- * The standard Java way of doing this is to use streams, which is very expensive.
- *
- * @return the first matching element, or null if none.
- */
- @Nullable
- public static <T> T findFirst(@NonNull final Collection<T> haystack,
- @NonNull final Predicate<T> p) {
- for (final T needle : haystack) {
- if (p.test(needle)) return needle;
- }
- return null;
- }
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index e24e982bc9a8..e35fda1ee76d 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -57,6 +57,8 @@ interface ILockSettings {
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
+ void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId);
+ void scheduleNonStrongBiometricIdleTimeout(int userId);
void systemReady();
void userPresent(int userId);
int getStrongAuthForUser(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 864429c98989..d9b290267c96 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -49,6 +49,7 @@ import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
@@ -1382,6 +1383,22 @@ public class LockPatternUtils {
}
}
+ public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ try {
+ getLockSettings().reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not report successful biometric unlock", e);
+ }
+ }
+
+ public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+ try {
+ getLockSettings().scheduleNonStrongBiometricIdleTimeout(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not schedule non-strong biometric idle timeout", e);
+ }
+ }
+
/**
* @see StrongAuthTracker#getStrongAuthForUser
*/
@@ -1557,7 +1574,8 @@ public class LockPatternUtils {
SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN})
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
+ STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1604,6 +1622,12 @@ public class LockPatternUtils {
public static final int STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE = 0x40;
/**
+ * Strong authentication is required because it hasn't been used for a time after a
+ * non-strong biometric (i.e. weak or convenience biometric) is used to unlock device.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT = 0x80;
+
+ /**
* Strong auth flags that do not prevent biometric methods from being accepted as auth.
* If any other flags are set, biometric authentication is disabled.
*/
@@ -1614,6 +1638,10 @@ public class LockPatternUtils {
private final H mHandler;
private final int mDefaultStrongAuthFlags;
+ private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser =
+ new SparseBooleanArray();
+ private final boolean mDefaultIsNonStrongBiometricAllowed = true;
+
public StrongAuthTracker(Context context) {
this(context, Looper.myLooper());
}
@@ -1657,8 +1685,21 @@ public class LockPatternUtils {
* @return true if unlocking with a biometric method alone is allowed for {@code userId}
* by the current strong authentication requirements.
*/
- public boolean isBiometricAllowedForUser(int userId) {
- return (getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0;
+ public boolean isBiometricAllowedForUser(boolean isStrongBiometric, int userId) {
+ boolean allowed = ((getStrongAuthForUser(userId) & ~ALLOWING_BIOMETRIC) == 0);
+ if (!isStrongBiometric) {
+ allowed &= isNonStrongBiometricAllowedAfterIdleTimeout(userId);
+ }
+ return allowed;
+ }
+
+ /**
+ * @return true if unlocking with a non-strong (i.e. weak or convenience) biometric method
+ * alone is allowed for {@code userId}, otherwise returns false.
+ */
+ public boolean isNonStrongBiometricAllowedAfterIdleTimeout(int userId) {
+ return mIsNonStrongBiometricAllowedForUser.get(userId,
+ mDefaultIsNonStrongBiometricAllowed);
}
/**
@@ -1667,6 +1708,12 @@ public class LockPatternUtils {
public void onStrongAuthRequiredChanged(int userId) {
}
+ /**
+ * Called when whether non-strong biometric is allowed for {@code userId} changed.
+ */
+ public void onIsNonStrongBiometricAllowedChanged(int userId) {
+ }
+
protected void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
int userId) {
int oldValue = getStrongAuthForUser(userId);
@@ -1680,6 +1727,18 @@ public class LockPatternUtils {
}
}
+ protected void handleIsNonStrongBiometricAllowedChanged(boolean allowed,
+ int userId) {
+ boolean oldValue = isNonStrongBiometricAllowedAfterIdleTimeout(userId);
+ if (allowed != oldValue) {
+ if (allowed == mDefaultIsNonStrongBiometricAllowed) {
+ mIsNonStrongBiometricAllowedForUser.delete(userId);
+ } else {
+ mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
+ }
+ onIsNonStrongBiometricAllowedChanged(userId);
+ }
+ }
protected final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
@Override
@@ -1688,10 +1747,17 @@ public class LockPatternUtils {
mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
strongAuthFlags, userId).sendToTarget();
}
+
+ @Override
+ public void onIsNonStrongBiometricAllowedChanged(boolean allowed, int userId) {
+ mHandler.obtainMessage(H.MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED,
+ allowed ? 1 : 0, userId).sendToTarget();
+ }
};
private class H extends Handler {
static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
+ static final int MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED = 2;
public H(Looper looper) {
super(looper);
@@ -1703,6 +1769,10 @@ public class LockPatternUtils {
case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
break;
+ case MSG_ON_IS_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED:
+ handleIsNonStrongBiometricAllowedChanged(msg.arg1 == 1 /* allowed */,
+ msg.arg2);
+ break;
}
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5912f4059548..d27be275f312 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -52,20 +52,11 @@ cc_library_shared {
"system/media/private/camera/include",
],
- static_libs: [
- "libandroid_graphics",
- ],
-
- whole_static_libs: ["libandroid_graphics"],
-
- export_static_lib_headers: ["libandroid_graphics"],
-
shared_libs: [
"libbase",
"libcutils",
"libharfbuzz_ng",
"libhwui",
- "libjpeg",
"liblog",
"libminikin",
"libnativehelper",
@@ -107,6 +98,7 @@ cc_library_shared {
"android_database_SQLiteGlobal.cpp",
"android_database_SQLiteDebug.cpp",
"android_graphics_GraphicBuffer.cpp",
+ "android_graphics_SurfaceTexture.cpp",
"android_view_CompositionSamplingListener.cpp",
"android_view_DisplayEventReceiver.cpp",
"android_view_InputChannel.cpp",
@@ -182,8 +174,6 @@ cc_library_shared {
"android_hardware_UsbRequest.cpp",
"android_hardware_location_ActivityRecognitionHardware.cpp",
"android_util_FileObserver.cpp",
- "android/graphics/GraphicsStatsService.cpp",
- "android/graphics/SurfaceTexture.cpp",
"android/opengl/poly_clip.cpp", // TODO: .arm
"android/opengl/util.cpp",
"android_server_NetworkManagementSocketTagger.cpp",
@@ -324,153 +314,3 @@ cc_library_shared {
},
},
}
-
-cc_library_static {
- name: "libandroid_graphics",
- host_supported: true,
- cflags: [
- "-Wno-unused-parameter",
- "-Wno-non-virtual-dtor",
- "-Wno-maybe-uninitialized",
- "-Wno-parentheses",
-
- "-DGL_GLEXT_PROTOTYPES",
- "-DEGL_EGLEXT_PROTOTYPES",
-
- "-DU_USING_ICU_NAMESPACE=0",
-
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wunused",
- "-Wunreachable-code",
- ],
-
- cppflags: ["-Wno-conversion-null"],
-
- srcs: [
- "android/graphics/apex/android_matrix.cpp",
- "android/graphics/apex/android_paint.cpp",
- "android/graphics/apex/android_region.cpp",
-
- "android_graphics_animation_NativeInterpolatorFactory.cpp",
- "android_graphics_animation_RenderNodeAnimator.cpp",
- "android_graphics_Canvas.cpp",
- "android_graphics_ColorSpace.cpp",
- "android_graphics_drawable_AnimatedVectorDrawable.cpp",
- "android_graphics_drawable_VectorDrawable.cpp",
- "android_graphics_HardwareRendererObserver.cpp",
- "android_graphics_Picture.cpp",
- "android_nio_utils.cpp",
- "android_view_DisplayListCanvas.cpp",
- "android_view_RenderNode.cpp",
- "android_util_PathParser.cpp",
-
- "android/graphics/Bitmap.cpp",
- "android/graphics/BitmapFactory.cpp",
- "android/graphics/ByteBufferStreamAdaptor.cpp",
- "android/graphics/Camera.cpp",
- "android/graphics/CanvasProperty.cpp",
- "android/graphics/ColorFilter.cpp",
- "android/graphics/CreateJavaOutputStreamAdaptor.cpp",
- "android/graphics/FontFamily.cpp",
- "android/graphics/FontUtils.cpp",
- "android/graphics/Graphics.cpp",
- "android/graphics/ImageDecoder.cpp",
- "android/graphics/Interpolator.cpp",
- "android/graphics/MaskFilter.cpp",
- "android/graphics/Matrix.cpp",
- "android/graphics/NinePatch.cpp",
- "android/graphics/NinePatchPeeker.cpp",
- "android/graphics/Paint.cpp",
- "android/graphics/PaintFilter.cpp",
- "android/graphics/Path.cpp",
- "android/graphics/PathEffect.cpp",
- "android/graphics/PathMeasure.cpp",
- "android/graphics/Picture.cpp",
- "android/graphics/Region.cpp",
- "android/graphics/Shader.cpp",
- "android/graphics/Typeface.cpp",
- "android/graphics/Utils.cpp",
- "android/graphics/YuvToJpegEncoder.cpp",
- "android/graphics/fonts/Font.cpp",
- "android/graphics/fonts/FontFamily.cpp",
- "android/graphics/text/LineBreaker.cpp",
- "android/graphics/text/MeasuredText.cpp",
- ],
-
- local_include_dirs: [
- "include", // NEEDED FOR ANDROID RUNTIME
- "android/graphics",
- "android/graphics/apex/include",
- ],
-
- export_include_dirs: [
- "android/graphics/apex/include",
- ],
-
- include_dirs: [
- "external/skia/include/private",
- "external/skia/src/codec",
- "external/skia/src/core",
- "external/skia/src/effects",
- "external/skia/src/image",
- "external/skia/src/images",
- ],
-
- shared_libs: [
- "libbase",
- "libcutils",
- "libharfbuzz_ng",
- "libhwui",
- "liblog",
- "libminikin",
- "libnativehelper",
- "libz",
- "libziparchive",
- "libjpeg",
- ],
-
- target: {
- android: {
- srcs: [ // sources that depend on android only libraries
- "android/graphics/apex/android_canvas.cpp",
- "android/graphics/apex/android_bitmap.cpp",
- "android/graphics/apex/renderthread.cpp",
- "android/graphics/apex/jni_runtime.cpp",
-
- "android_view_TextureLayer.cpp",
- "android_view_ThreadedRenderer.cpp",
- "android/graphics/AnimatedImageDrawable.cpp",
- "android/graphics/BitmapRegionDecoder.cpp",
- "android/graphics/GIFMovie.cpp",
- "android/graphics/Movie.cpp",
- "android/graphics/MovieImpl.cpp",
- "android/graphics/pdf/PdfDocument.cpp",
- "android/graphics/pdf/PdfEditor.cpp",
- "android/graphics/pdf/PdfRenderer.cpp",
- "android/graphics/pdf/PdfUtils.cpp",
- ],
- shared_libs: [
- "libandroidfw",
- "libEGL",
- "libmediandk",
- "libnativedisplay",
- "libnativewindow",
- "libpdfium",
- ],
- static_libs: [
- "libgif",
- ],
- },
- host: {
- cflags: [
- "-Wno-unused-const-variable",
- "-Wno-unused-function",
- ],
- static_libs: [
- "libandroidfw",
- ],
- }
- },
-}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4879478733e6..c41398c97ca0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -115,6 +115,7 @@ extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_content_res_ApkAssets(JNIEnv* env);
extern int register_android_graphics_BLASTBufferQueue(JNIEnv* env);
+extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_InputApplicationHandle(JNIEnv* env);
extern int register_android_view_InputWindowHandle(JNIEnv* env);
@@ -1484,6 +1485,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_classes),
REG_JNI(register_android_graphics_BLASTBufferQueue),
REG_JNI(register_android_graphics_GraphicBuffer),
+ REG_JNI(register_android_graphics_SurfaceTexture),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteConnection),
REG_JNI(register_android_database_SQLiteGlobal),
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index 7ee509b4ecb4..77c1a1097240 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -34,19 +34,6 @@ using namespace std;
static JavaVM* javaVM;
-extern int register_android_graphics_Bitmap(JNIEnv*);
-extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
-extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
-extern int register_android_graphics_Graphics(JNIEnv* env);
-extern int register_android_graphics_ImageDecoder(JNIEnv*);
-extern int register_android_graphics_Interpolator(JNIEnv* env);
-extern int register_android_graphics_MaskFilter(JNIEnv* env);
-extern int register_android_graphics_NinePatch(JNIEnv*);
-extern int register_android_graphics_PathEffect(JNIEnv* env);
-extern int register_android_graphics_Shader(JNIEnv* env);
-extern int register_android_graphics_Typeface(JNIEnv* env);
-
namespace android {
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
@@ -54,25 +41,6 @@ extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_content_res_ApkAssets(JNIEnv* env);
-extern int register_android_graphics_Canvas(JNIEnv* env);
-extern int register_android_graphics_ColorFilter(JNIEnv* env);
-extern int register_android_graphics_ColorSpace(JNIEnv* env);
-extern int register_android_graphics_DrawFilter(JNIEnv* env);
-extern int register_android_graphics_FontFamily(JNIEnv* env);
-extern int register_android_graphics_Matrix(JNIEnv* env);
-extern int register_android_graphics_Paint(JNIEnv* env);
-extern int register_android_graphics_Path(JNIEnv* env);
-extern int register_android_graphics_PathMeasure(JNIEnv* env);
-extern int register_android_graphics_Picture(JNIEnv* env);
-extern int register_android_graphics_Region(JNIEnv* env);
-extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
-extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
-extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
-extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
-extern int register_android_graphics_fonts_Font(JNIEnv* env);
-extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
-extern int register_android_graphics_text_LineBreaker(JNIEnv* env);
-extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_SystemClock(JNIEnv* env);
@@ -81,10 +49,7 @@ extern int register_android_os_Trace(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
-extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
-extern int register_android_view_RenderNode(JNIEnv* env);
-extern int register_android_view_DisplayListCanvas(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
#define REG_JNI(name) { name }
@@ -103,46 +68,6 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
#endif
{"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)},
{"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
- {"android.graphics.Bitmap", REG_JNI(register_android_graphics_Bitmap)},
- {"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
- {"android.graphics.ByteBufferStreamAdaptor",
- REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
- {"android.graphics.Canvas", REG_JNI(register_android_graphics_Canvas)},
- {"android.graphics.RenderNode", REG_JNI(register_android_view_RenderNode)},
- {"android.graphics.ColorFilter", REG_JNI(register_android_graphics_ColorFilter)},
- {"android.graphics.ColorSpace", REG_JNI(register_android_graphics_ColorSpace)},
- {"android.graphics.CreateJavaOutputStreamAdaptor",
- REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor)},
- {"android.graphics.DrawFilter", REG_JNI(register_android_graphics_DrawFilter)},
- {"android.graphics.FontFamily", REG_JNI(register_android_graphics_FontFamily)},
- {"android.graphics.Graphics", REG_JNI(register_android_graphics_Graphics)},
- {"android.graphics.ImageDecoder", REG_JNI(register_android_graphics_ImageDecoder)},
- {"android.graphics.Interpolator", REG_JNI(register_android_graphics_Interpolator)},
- {"android.graphics.MaskFilter", REG_JNI(register_android_graphics_MaskFilter)},
- {"android.graphics.Matrix", REG_JNI(register_android_graphics_Matrix)},
- {"android.graphics.NinePatch", REG_JNI(register_android_graphics_NinePatch)},
- {"android.graphics.Paint", REG_JNI(register_android_graphics_Paint)},
- {"android.graphics.Path", REG_JNI(register_android_graphics_Path)},
- {"android.graphics.PathEffect", REG_JNI(register_android_graphics_PathEffect)},
- {"android.graphics.PathMeasure", REG_JNI(register_android_graphics_PathMeasure)},
- {"android.graphics.Picture", REG_JNI(register_android_graphics_Picture)},
- {"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
- {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
- {"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
- {"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
- {"android.graphics.animation.NativeInterpolatorFactory",
- REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
- {"android.graphics.animation.RenderNodeAnimator",
- REG_JNI(register_android_graphics_animation_RenderNodeAnimator)},
- {"android.graphics.drawable.AnimatedVectorDrawable",
- REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable)},
- {"android.graphics.drawable.VectorDrawable",
- REG_JNI(register_android_graphics_drawable_VectorDrawable)},
- {"android.graphics.fonts.Font", REG_JNI(register_android_graphics_fonts_Font)},
- {"android.graphics.fonts.FontFamily", REG_JNI(register_android_graphics_fonts_FontFamily)},
- {"android.graphics.text.LineBreaker", REG_JNI(register_android_graphics_text_LineBreaker)},
- {"android.graphics.text.MeasuredText",
- REG_JNI(register_android_graphics_text_MeasuredText)},
#ifdef __linux__
{"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)},
{"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)},
@@ -153,7 +78,6 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)},
{"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
{"android.util.Log", REG_JNI(register_android_util_Log)},
- {"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
{"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
{"com.android.internal.util.VirtualRefBasePtr",
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)},
diff --git a/core/jni/android_graphics_GraphicBuffer.cpp b/core/jni/android_graphics_GraphicBuffer.cpp
index b6d50898a057..25a733234313 100644
--- a/core/jni/android_graphics_GraphicBuffer.cpp
+++ b/core/jni/android_graphics_GraphicBuffer.cpp
@@ -31,6 +31,7 @@
#include <android/native_window.h>
#include <android/graphics/canvas.h>
#include <android_runtime/android_graphics_GraphicBuffer.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <private/gui/ComposerService.h>
@@ -260,6 +261,16 @@ jobject android_graphics_GraphicBuffer_createFromAHardwareBuffer(JNIEnv* env,
return obj;
}
+// ----------------------------------------------------------------------------
+// AHB to GraphicBuffer Converter
+// ----------------------------------------------------------------------------
+
+static jobject android_graphics_GraphicBuffer_createFromHardwareBuffer(JNIEnv* env, jobject clazz,
+ jobject hb) {
+ AHardwareBuffer* ahb = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, hb);
+ return android_graphics_GraphicBuffer_createFromAHardwareBuffer(env, ahb);
+}
+
};
using namespace android;
@@ -283,7 +294,10 @@ static const JNINativeMethod gMethods[] = {
{ "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
(void*) android_graphics_GraphicBuffer_unlockCanvasAndPost },
{ "nWrapGraphicBuffer", "(J)J",
- (void*) android_graphics_GraphicBuffer_wrap }
+ (void*) android_graphics_GraphicBuffer_wrap },
+ { "nCreateFromHardwareBuffer",
+ "(Landroid/hardware/HardwareBuffer;)Landroid/graphics/GraphicBuffer;",
+ (void*) android_graphics_GraphicBuffer_createFromHardwareBuffer }
};
int register_android_graphics_GraphicBuffer(JNIEnv* env) {
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android_graphics_SurfaceTexture.cpp
index 2aca31733599..0909ce7ff23b 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android_graphics_SurfaceTexture.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "SurfaceTexture"
#include <stdio.h>
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index f03f42737134..8bb4d503cc82 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -47,28 +47,32 @@ static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+ field_signature);
return res;
}
static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s", method_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name,
+ method_signature);
return res;
}
static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s with signature %s", field_name,
+ field_signature);
return res;
}
static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s", method_name);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s with signature %s",
+ method_name, method_signature);
return res;
}
diff --git a/core/proto/android/server/peopleservice.proto b/core/proto/android/server/peopleservice.proto
index e476c523607c..e65a2abce4f0 100644
--- a/core/proto/android/server/peopleservice.proto
+++ b/core/proto/android/server/peopleservice.proto
@@ -50,6 +50,9 @@ message ConversationInfoProto {
// Integer representation of conversation bit flags.
optional int32 conversation_flags = 6;
+
+ // The phone number of the contact.
+ optional string contact_phone_number = 7;
}
// On disk data of events.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ddfc4b8e94a4..814b8acd63ac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3084,8 +3084,7 @@
<!-- Allows SystemUI to request third party controls.
<p>Should only be requested by the System and required by
- ControlsService declarations.
- @hide
+ {@link android.service.controls.ControlsProviderService} declarations.
-->
<permission android:name="android.permission.BIND_CONTROLS"
android:protectionLevel="signature" />
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index c0de6936dd12..5676049fb940 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -90,7 +90,7 @@
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <com.android.internal.app.ResolverViewPager
+ <com.android.internal.widget.ViewPager
android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 68c86b263a75..482a41647d59 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1278,20 +1278,21 @@
<integer name="config_screenBrightnessSettingDefault">102</integer>
<!-- Minimum screen brightness setting allowed by power manager.
- The user is forbidden from setting the brightness below this level.
- Equivalent to 10/255. -->
- <item name="config_screenBrightnessSettingMinimumFloat" format="float" type="dimen">0.035433073</item>
+ -2 is invalid so setting will resort to int value specified above.
+ Set this to 0.0 to allow screen to go to minimal brightness.
+ The user is forbidden from setting the brightness below this level. -->
+ <item name="config_screenBrightnessSettingMinimumFloat" format="float" type="dimen">-2</item>
<!-- Maximum screen brightness allowed by the power manager.
- The user is forbidden from setting the brightness above this level.
- This value is a fraction between 3.5% and 100%. -->
- <item name="config_screenBrightnessSettingMaximumFloat" format="float" type="dimen">1.0</item>
+ -2 is invalid so setting will resort to int value specified above.
+ Set this to 1.0 for maximum brightness range.
+ The user is forbidden from setting the brightness above this level. -->
+ <item name="config_screenBrightnessSettingMaximumFloat" format="float" type="dimen">-2</item>
- <!-- Default screen brightness setting.
- Must be in the range specified by minimum and maximum.
- This value is a fraction between 3.5% and 100%.
- Equivalent to 102/255 (default for this device) -->
- <item name="config_screenBrightnessSettingDefaultFloat" format="float" type="dimen">0.397637795276</item>
+ <!-- Default screen brightness setting set.
+ -2 is invalid so setting will resort to int value specified above.
+ Must be in the range specified by minimum and maximum. -->
+ <item name="config_screenBrightnessSettingDefaultFloat" format="float" type="dimen">-2</item>
<!-- Note: This setting is deprecated, please use
config_screenBrightnessSettingForVrDefaultFloat instead -->
@@ -2588,6 +2589,18 @@
<string name="config_customAdbPublicKeyConfirmationSecondaryUserComponent"
>com.android.systemui/com.android.systemui.usb.UsbDebuggingSecondaryUserActivity</string>
+ <!-- Name of the activity or service that prompts the user to reject, accept, or whitelist
+ a wireless network for wireless debugging.
+ Can be customized for other product types -->
+ <string name="config_customAdbWifiNetworkConfirmationComponent"
+ >com.android.systemui/com.android.systemui.wifi.WifiDebuggingActivity</string>
+
+ <!-- Name of the activity that prompts the secondary user to acknowledge she/he needs to
+ switch to the primary user to enable wireless debugging.
+ Can be customized for other product types -->
+ <string name="config_customAdbWifiNetworkConfirmationSecondaryUserComponent"
+ >com.android.systemui/com.android.systemui.wifi.WifiDebuggingSecondaryUserActivity</string>
+
<!-- Component name of the activity that shows the usb containment status. -->
<string name="config_usbContaminantActivity" translatable="false"
>com.android.systemui/com.android.systemui.usb.UsbContaminantActivity</string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 48049b44dd29..4f221d0d85fd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -781,9 +781,6 @@
<dimen name="chooser_action_button_icon_size">18dp</dimen>
- <!-- Assistant handles -->
- <dimen name="assist_handle_shadow_radius">2dp</dimen>
-
<!-- For Waterfall Display -->
<dimen name="waterfall_display_left_edge_size">0px</dimen>
<dimen name="waterfall_display_top_edge_size">0px</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d513e2b5a9e5..144573641654 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3527,6 +3527,12 @@
<!-- Message of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_message">Tap to turn off USB debugging</string>
<string name="adb_active_notification_message" product="tv">Select to disable USB debugging.</string>
+ <!-- Title of notification shown when ADB Wireless is actively connected to the phone. [CHAR LIMIT=NONE] -->
+ <string name="adbwifi_active_notification_title">Wireless debugging connected</string>
+ <!-- Message of notification shown when ADB Wireless is actively connected to the phone. [CHAR LIMIT=NONE] -->
+ <string name="adbwifi_active_notification_message">Tap to turn off wireless debugging</string>
+ <!-- Message of notification shown when ADB Wireless is actively connected to the TV. [CHAR LIMIT=NONE] -->
+ <string name="adbwifi_active_notification_message" product="tv">Select to disable wireless debugging.</string>
<!-- Title of notification shown when Test Harness Mode is enabled. [CHAR LIMIT=NONE] -->
<string name="test_harness_mode_notification_title">Test Harness Mode enabled</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1c9e2cd72f28..a3da41101ad3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2009,6 +2009,8 @@
<java-symbol type="string" name="accessibility_binding_label" />
<java-symbol type="string" name="adb_active_notification_message" />
<java-symbol type="string" name="adb_active_notification_title" />
+ <java-symbol type="string" name="adbwifi_active_notification_message" />
+ <java-symbol type="string" name="adbwifi_active_notification_title" />
<java-symbol type="string" name="test_harness_mode_notification_title" />
<java-symbol type="string" name="test_harness_mode_notification_message" />
<java-symbol type="string" name="console_running_notification_title" />
@@ -2154,6 +2156,8 @@
<java-symbol type="integer" name="config_attentiveWarningDuration" />
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" />
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationSecondaryUserComponent" />
+ <java-symbol type="string" name="config_customAdbWifiNetworkConfirmationComponent" />
+ <java-symbol type="string" name="config_customAdbWifiNetworkConfirmationSecondaryUserComponent" />
<java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
<java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
<java-symbol type="string" name="config_platformVpnConfirmDialogComponent" />
@@ -3840,9 +3844,6 @@
<!-- For App Standby -->
<java-symbol type="string" name="as_app_forced_to_restricted_bucket" />
- <!-- Assistant handles -->
- <java-symbol type="dimen" name="assist_handle_shadow_radius" />
-
<!-- For Waterfall Display -->
<java-symbol type="dimen" name="waterfall_display_left_edge_size" />
<java-symbol type="dimen" name="waterfall_display_top_edge_size" />
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
index 9f0af60f33b7..f0e70a53b572 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityShortcutInfoTest.java
@@ -92,7 +92,7 @@ public class AccessibilityShortcutInfoTest {
@Test
public void testLoadAnimatedImage() {
assertNotNull("Can't find animated image",
- mShortcutInfo.loadAnimatedImage(mPackageManager));
+ mShortcutInfo.loadAnimatedImage(mTargetContext));
}
@Test
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 78c4420b9496..1737bd0fa20b 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -234,4 +234,12 @@ public class ContentResolverTest {
assertThat(type).isNull();
assertThat(end).isLessThan(start + 5000);
}
+
+ @Test
+ public void testCanonicalize() {
+ Uri canonical = mResolver.canonicalize(
+ Uri.parse("content://android.content.FakeProviderRemote/something"));
+ assertThat(canonical).isEqualTo(
+ Uri.parse("content://android.content.FakeProviderRemote/canonical"));
+ }
}
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index 7b9bdbcd7a17..1d7ba5d9be46 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -54,4 +54,10 @@ public class FakeProviderRemote extends ContentProvider {
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
+
+ @Override
+ public Uri canonicalize(Uri uri) {
+ return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority())
+ .appendPath("canonical").build();
+ }
}
diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
index 78c88d71d953..4c2ca7eefcc1 100644
--- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
+++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java
@@ -25,9 +25,13 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -44,6 +48,7 @@ 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;
@@ -59,6 +64,11 @@ import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
public class ControlProviderServiceTest {
+ private static final ComponentName TEST_SYSUI_COMPONENT =
+ ComponentName.unflattenFromString("sysui/.test.cls");
+ private static final ComponentName TEST_COMPONENT =
+ ComponentName.unflattenFromString("test.pkg/.test.cls");
+
private IBinder mToken = new Binder();
@Mock
private IControlsActionCallback.Stub mActionCallback;
@@ -66,6 +76,12 @@ public class ControlProviderServiceTest {
private IControlsSubscriber.Stub mSubscriber;
@Mock
private IIntentSender mIIntentSender;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private Context mContext;
+ @Captor
+ private ArgumentCaptor<Intent> mIntentArgumentCaptor;
private PendingIntent mPendingIntent;
private FakeControlsProviderService mControlsProviderService;
@@ -81,6 +97,10 @@ public class ControlProviderServiceTest {
when(mSubscriber.asBinder()).thenCallRealMethod();
when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber);
+ when(mResources.getString(com.android.internal.R.string.config_systemUIServiceComponent))
+ .thenReturn(TEST_SYSUI_COMPONENT.flattenToString());
+ when(mContext.getResources()).thenReturn(mResources);
+
Bundle b = new Bundle();
b.putBinder(ControlsProviderService.CALLBACK_TOKEN, mToken);
Intent intent = new Intent();
@@ -223,6 +243,21 @@ public class ControlProviderServiceTest {
ControlAction.RESPONSE_OK);
}
+ @Test
+ public void testRequestAdd() {
+ Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build();
+ ControlsProviderService.requestAddControl(mContext, TEST_COMPONENT, control);
+
+ verify(mContext).sendBroadcast(mIntentArgumentCaptor.capture(),
+ eq(Manifest.permission.BIND_CONTROLS));
+ Intent intent = mIntentArgumentCaptor.getValue();
+ assertEquals(ControlsProviderService.ACTION_ADD_CONTROL, intent.getAction());
+ assertEquals(TEST_SYSUI_COMPONENT.getPackageName(), intent.getPackage());
+ assertEquals(TEST_COMPONENT, intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME));
+ assertTrue(equals(control,
+ intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL)));
+ }
+
private static boolean equals(Control c1, Control c2) {
if (c1 == c2) return true;
if (c1 == null || c2 == null) return false;
diff --git a/core/tests/coretests/src/android/util/EventLogTest.java b/core/tests/coretests/src/android/util/EventLogTest.java
new file mode 100644
index 000000000000..94e72c4a8d52
--- /dev/null
+++ b/core/tests/coretests/src/android/util/EventLogTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.util.EventLog.Event;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Unit tests for {@link android.util.EventLog} */
+public class EventLogTest {
+
+ @Test
+ public void testWithNewData() throws Throwable {
+ Event event = createEvent(() -> {
+ EventLog.writeEvent(314, 123);
+ }, 314);
+
+ assertTrue(event.withNewData(12345678L).getData().equals(12345678L));
+ assertTrue(event.withNewData(2.718f).getData().equals(2.718f));
+ assertTrue(event.withNewData("test string").getData().equals("test string"));
+
+ Object[] objects = ((Object[]) event.withNewData(
+ new Object[] {111, 2.22f, 333L, "444"}).getData());
+ assertEquals(4, objects.length);
+ assertTrue(objects[0].equals(111));
+ assertTrue(objects[1].equals(2.22f));
+ assertTrue(objects[2].equals(333L));
+ assertTrue(objects[3].equals("444"));
+ }
+
+ /**
+ * Creates an Event object. Only the native code has the serialization and deserialization logic
+ * so need to actually emit a real log in order to generate the object.
+ */
+ private Event createEvent(Runnable generator, int expectedTag) throws Exception {
+ Long markerData = System.currentTimeMillis();
+ EventLog.writeEvent(expectedTag, markerData);
+ generator.run();
+
+ List<Event> events = new ArrayList<>();
+ // Give the message some time to show up in the log
+ Thread.sleep(20);
+ EventLog.readEvents(new int[] {expectedTag}, events);
+ for (int i = 0; i < events.size() - 1; i++) {
+ if (markerData.equals(events.get(i).getData())) {
+ return events.get(i + 1);
+ }
+ }
+ throw new AssertionFailedError("Unable to locate marker event");
+ }
+}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 5b23dc0481cb..145fd8b824cf 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -709,6 +709,18 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-650040763": {
+ "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayRotation.java"
+ },
+ "-639305784": {
+ "message": "Could not report config changes to the window token client.",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowToken.java"
+ },
"-635082269": {
"message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
"level": "INFO",
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index c1e7a360fcc5..f7877590869a 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2240,7 +2240,7 @@ public final class Bitmap implements Parcelable {
*/
@UnsupportedAppUsage
public GraphicBuffer createGraphicBufferHandle() {
- return nativeCreateGraphicBufferHandle(mNativePtr);
+ return GraphicBuffer.createFromHardwareBuffer(getHardwareBuffer());
}
/**
@@ -2320,7 +2320,6 @@ public final class Bitmap implements Parcelable {
private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
long nativeColorSpace);
- private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
private static native HardwareBuffer nativeGetHardwareBuffer(long nativeBitmap);
private static native ColorSpace nativeComputeColorSpace(long nativePtr);
private static native void nativeSetColorSpace(long nativePtr, long nativeColorSpace);
diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java
index 99fa5eef7bbd..0430847857b6 100644
--- a/graphics/java/android/graphics/GraphicBuffer.java
+++ b/graphics/java/android/graphics/GraphicBuffer.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.compat.annotation.UnsupportedAppUsage;
+import android.hardware.HardwareBuffer;
import android.os.Parcel;
import android.os.Parcelable;
@@ -110,6 +111,14 @@ public class GraphicBuffer implements Parcelable {
}
/**
+ * For Bitmap until all usages are updated to AHB
+ * @hide
+ */
+ public static final GraphicBuffer createFromHardwareBuffer(HardwareBuffer buffer) {
+ return nCreateFromHardwareBuffer(buffer);
+ }
+
+ /**
* Returns the width of this buffer in pixels.
*/
public int getWidth() {
@@ -305,4 +314,5 @@ public class GraphicBuffer implements Parcelable {
private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
private static native long nWrapGraphicBuffer(long nativeObject);
+ private static native GraphicBuffer nCreateFromHardwareBuffer(HardwareBuffer buffer);
}
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index c12159cfd7a4..5858e3988486 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -280,7 +280,10 @@ public final class Outline {
* {@link android.os.Build.VERSION_CODES#Q}, it is no longer required to be
* convex.
*
- * @deprecated The path is no longer required to be convex. Use {@link #setPath} instead.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, the restriction
+ * that the path must be convex is removed. However, the API is misnamed until
+ * {@link android.os.Build.VERSION_CODES#R}, when {@link #setPath} is
+ * introduced. Use {@link #setPath} instead.
*/
@Deprecated
public void setConvexPath(@NonNull Path convexPath) {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index a7e17d13c9e1..acd90a7f10cf 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -34,6 +34,7 @@ import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
@@ -811,6 +812,10 @@ public final class KeyChain {
throw new NullPointerException("context == null");
}
ensureNotOnMainThread(context);
+ if (!UserManager.get(context).isUserUnlocked(user)) {
+ throw new IllegalStateException("User must be unlocked");
+ }
+
final CountDownLatch countDownLatch = new CountDownLatch(1);
final AtomicReference<IKeyChainService> keyChainService = new AtomicReference<>();
ServiceConnection keyChainServiceConnection = new ServiceConnection() {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 81dedda5341d..ac2fd98248d0 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -152,9 +152,235 @@ cc_defaults {
}
// ------------------------
+// APEX
+// ------------------------
+
+cc_library_headers {
+ name: "android_graphics_apex_headers",
+
+ host_supported: true,
+ export_include_dirs: [
+ "apex/include",
+ ],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ }
+}
+
+cc_defaults {
+ name: "android_graphics_apex",
+ host_supported: true,
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wno-non-virtual-dtor",
+ "-Wno-maybe-uninitialized",
+ "-Wno-parentheses",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ cppflags: ["-Wno-conversion-null"],
+
+ srcs: [
+ "apex/android_matrix.cpp",
+ "apex/android_paint.cpp",
+ "apex/android_region.cpp",
+ ],
+
+ header_libs: [ "android_graphics_apex_headers" ],
+
+ target: {
+ android: {
+ srcs: [ // sources that depend on android only libraries
+ "apex/android_bitmap.cpp",
+ "apex/android_canvas.cpp",
+ "apex/jni_runtime.cpp",
+ "apex/renderthread.cpp",
+ ],
+ },
+ host: {
+ srcs: [
+ "apex/LayoutlibLoader.cpp",
+ ],
+ }
+ },
+}
+
+// ------------------------
+// Android Graphics JNI
+// ------------------------
+
+cc_library_headers {
+ name: "android_graphics_jni_headers",
+
+ host_supported: true,
+ export_include_dirs: [
+ "jni",
+ ],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ }
+}
+
+cc_defaults {
+ name: "android_graphics_jni",
+ host_supported: true,
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wno-non-virtual-dtor",
+ "-Wno-maybe-uninitialized",
+ "-Wno-parentheses",
+
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+
+ "-DU_USING_ICU_NAMESPACE=0",
+
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ cppflags: ["-Wno-conversion-null"],
+
+ srcs: [
+ "jni/android_graphics_animation_NativeInterpolatorFactory.cpp",
+ "jni/android_graphics_animation_RenderNodeAnimator.cpp",
+ "jni/android_graphics_Canvas.cpp",
+ "jni/android_graphics_ColorSpace.cpp",
+ "jni/android_graphics_drawable_AnimatedVectorDrawable.cpp",
+ "jni/android_graphics_drawable_VectorDrawable.cpp",
+ "jni/android_graphics_HardwareRendererObserver.cpp",
+ "jni/android_graphics_Matrix.cpp",
+ "jni/android_graphics_Picture.cpp",
+ "jni/android_graphics_DisplayListCanvas.cpp",
+ "jni/android_graphics_RenderNode.cpp",
+ "jni/android_nio_utils.cpp",
+ "jni/android_util_PathParser.cpp",
+
+ "jni/Bitmap.cpp",
+ "jni/BitmapFactory.cpp",
+ "jni/ByteBufferStreamAdaptor.cpp",
+ "jni/Camera.cpp",
+ "jni/CanvasProperty.cpp",
+ "jni/ColorFilter.cpp",
+ "jni/CreateJavaOutputStreamAdaptor.cpp",
+ "jni/FontFamily.cpp",
+ "jni/FontUtils.cpp",
+ "jni/Graphics.cpp",
+ "jni/ImageDecoder.cpp",
+ "jni/Interpolator.cpp",
+ "jni/MaskFilter.cpp",
+ "jni/NinePatch.cpp",
+ "jni/NinePatchPeeker.cpp",
+ "jni/Paint.cpp",
+ "jni/PaintFilter.cpp",
+ "jni/Path.cpp",
+ "jni/PathEffect.cpp",
+ "jni/PathMeasure.cpp",
+ "jni/Picture.cpp",
+ "jni/Shader.cpp",
+ "jni/Typeface.cpp",
+ "jni/Utils.cpp",
+ "jni/YuvToJpegEncoder.cpp",
+ "jni/fonts/Font.cpp",
+ "jni/fonts/FontFamily.cpp",
+ "jni/text/LineBreaker.cpp",
+ "jni/text/MeasuredText.cpp",
+ ],
+
+ header_libs: [ "android_graphics_jni_headers" ],
+
+ include_dirs: [
+ "external/skia/include/private",
+ "external/skia/src/codec",
+ "external/skia/src/core",
+ "external/skia/src/effects",
+ "external/skia/src/image",
+ "external/skia/src/images",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libharfbuzz_ng",
+ "liblog",
+ "libminikin",
+ "libnativehelper",
+ "libz",
+ "libziparchive",
+ "libjpeg",
+ ],
+
+ target: {
+ android: {
+ srcs: [ // sources that depend on android only libraries
+ "jni/AnimatedImageDrawable.cpp",
+ "jni/android_graphics_TextureLayer.cpp",
+ "jni/android_graphics_HardwareRenderer.cpp",
+ "jni/BitmapRegionDecoder.cpp",
+ "jni/GIFMovie.cpp",
+ "jni/GraphicsStatsService.cpp",
+ "jni/Movie.cpp",
+ "jni/MovieImpl.cpp",
+ "jni/Region.cpp", // requires libbinder_ndk
+ "jni/pdf/PdfDocument.cpp",
+ "jni/pdf/PdfEditor.cpp",
+ "jni/pdf/PdfRenderer.cpp",
+ "jni/pdf/PdfUtils.cpp",
+ ],
+ shared_libs: [
+ "libandroidfw",
+ "libbinder",
+ "libbinder_ndk",
+ "libmediandk",
+ "libnativedisplay",
+ "libnativewindow",
+ "libstatspull",
+ "libstatssocket",
+ "libpdfium",
+ ],
+ static_libs: [
+ "libgif",
+ "libstatslog",
+ ],
+ },
+ host: {
+ cflags: [
+ "-Wno-unused-const-variable",
+ "-Wno-unused-function",
+ ],
+ static_libs: [
+ "libandroidfw",
+ ],
+ }
+ },
+}
+
+// ------------------------
// library
// ------------------------
+cc_library_headers {
+ name: "libhwui_internal_headers",
+
+ host_supported: true,
+ export_include_dirs: [
+ ".",
+ ],
+ header_libs: [ "android_graphics_jni_headers" ],
+ export_header_lib_headers: [ "android_graphics_jni_headers" ],
+}
+
cc_defaults {
name: "libhwui_defaults",
defaults: ["hwui_defaults"],
@@ -205,11 +431,8 @@ cc_defaults {
export_proto_headers: true,
},
- export_include_dirs: ["."],
-
target: {
android: {
-
srcs: [
"hwui/AnimatedImageThread.cpp",
"pipeline/skia/ATraceMemoryDump.cpp",
@@ -274,7 +497,10 @@ cc_library {
host_supported: true,
defaults: [
"libhwui_defaults",
+ "android_graphics_apex",
+ "android_graphics_jni",
],
+ export_header_lib_headers: ["android_graphics_apex_headers"],
}
cc_library_static {
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 6d4a0c6421d9..c24224cbbd67 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -18,9 +18,6 @@
#include <log/log.h>
#include <utils/Errors.h>
-#include <mutex>
-#include <thread>
-
#include "Properties.h"
namespace android {
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
new file mode 100644
index 000000000000..4bbf1214bdcf
--- /dev/null
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#include "graphics_jni_helpers.h"
+
+#include <GraphicsJNI.h>
+#include <SkGraphics.h>
+
+#include <sstream>
+#include <iostream>
+#include <unicode/putil.h>
+#include <unordered_map>
+#include <vector>
+
+using namespace std;
+
+/*
+ * This is responsible for setting up the JNI environment for communication between
+ * the Java and native parts of layoutlib, including registering native methods.
+ * This is mostly achieved by copying the way it is done in the platform
+ * (see AndroidRuntime.cpp).
+ */
+
+static JavaVM* javaVM;
+
+extern int register_android_graphics_Bitmap(JNIEnv*);
+extern int register_android_graphics_BitmapFactory(JNIEnv*);
+extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_Graphics(JNIEnv* env);
+extern int register_android_graphics_ImageDecoder(JNIEnv*);
+extern int register_android_graphics_Interpolator(JNIEnv* env);
+extern int register_android_graphics_MaskFilter(JNIEnv* env);
+extern int register_android_graphics_NinePatch(JNIEnv*);
+extern int register_android_graphics_PathEffect(JNIEnv* env);
+extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_Typeface(JNIEnv* env);
+
+namespace android {
+
+extern int register_android_graphics_Canvas(JNIEnv* env);
+extern int register_android_graphics_ColorFilter(JNIEnv* env);
+extern int register_android_graphics_ColorSpace(JNIEnv* env);
+extern int register_android_graphics_DrawFilter(JNIEnv* env);
+extern int register_android_graphics_FontFamily(JNIEnv* env);
+extern int register_android_graphics_Matrix(JNIEnv* env);
+extern int register_android_graphics_Paint(JNIEnv* env);
+extern int register_android_graphics_Path(JNIEnv* env);
+extern int register_android_graphics_PathMeasure(JNIEnv* env);
+extern int register_android_graphics_Picture(JNIEnv* env);
+//extern int register_android_graphics_Region(JNIEnv* env);
+extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
+extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
+extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
+extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
+extern int register_android_graphics_fonts_Font(JNIEnv* env);
+extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
+extern int register_android_graphics_text_LineBreaker(JNIEnv* env);
+extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
+extern int register_android_util_PathParser(JNIEnv* env);
+extern int register_android_view_RenderNode(JNIEnv* env);
+extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+
+#define REG_JNI(name) { name }
+struct RegJNIRec {
+ int (*mProc)(JNIEnv*);
+};
+
+// Map of all possible class names to register to their corresponding JNI registration function pointer
+// The actual list of registered classes will be determined at runtime via the 'native_classes' System property
+static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
+ {"android.graphics.Bitmap", REG_JNI(register_android_graphics_Bitmap)},
+ {"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
+ {"android.graphics.ByteBufferStreamAdaptor",
+ REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
+ {"android.graphics.Canvas", REG_JNI(register_android_graphics_Canvas)},
+ {"android.graphics.RenderNode", REG_JNI(register_android_view_RenderNode)},
+ {"android.graphics.ColorFilter", REG_JNI(register_android_graphics_ColorFilter)},
+ {"android.graphics.ColorSpace", REG_JNI(register_android_graphics_ColorSpace)},
+ {"android.graphics.CreateJavaOutputStreamAdaptor",
+ REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor)},
+ {"android.graphics.DrawFilter", REG_JNI(register_android_graphics_DrawFilter)},
+ {"android.graphics.FontFamily", REG_JNI(register_android_graphics_FontFamily)},
+ {"android.graphics.Graphics", REG_JNI(register_android_graphics_Graphics)},
+ {"android.graphics.ImageDecoder", REG_JNI(register_android_graphics_ImageDecoder)},
+ {"android.graphics.Interpolator", REG_JNI(register_android_graphics_Interpolator)},
+ {"android.graphics.MaskFilter", REG_JNI(register_android_graphics_MaskFilter)},
+ {"android.graphics.Matrix", REG_JNI(register_android_graphics_Matrix)},
+ {"android.graphics.NinePatch", REG_JNI(register_android_graphics_NinePatch)},
+ {"android.graphics.Paint", REG_JNI(register_android_graphics_Paint)},
+ {"android.graphics.Path", REG_JNI(register_android_graphics_Path)},
+ {"android.graphics.PathEffect", REG_JNI(register_android_graphics_PathEffect)},
+ {"android.graphics.PathMeasure", REG_JNI(register_android_graphics_PathMeasure)},
+ {"android.graphics.Picture", REG_JNI(register_android_graphics_Picture)},
+ {"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
+// {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
+ {"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
+ {"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
+ {"android.graphics.animation.NativeInterpolatorFactory",
+ REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
+ {"android.graphics.animation.RenderNodeAnimator",
+ REG_JNI(register_android_graphics_animation_RenderNodeAnimator)},
+ {"android.graphics.drawable.AnimatedVectorDrawable",
+ REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable)},
+ {"android.graphics.drawable.VectorDrawable",
+ REG_JNI(register_android_graphics_drawable_VectorDrawable)},
+ {"android.graphics.fonts.Font", REG_JNI(register_android_graphics_fonts_Font)},
+ {"android.graphics.fonts.FontFamily", REG_JNI(register_android_graphics_fonts_FontFamily)},
+ {"android.graphics.text.LineBreaker", REG_JNI(register_android_graphics_text_LineBreaker)},
+ {"android.graphics.text.MeasuredText",
+ REG_JNI(register_android_graphics_text_MeasuredText)},
+ {"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
+};
+
+static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap,
+ const vector<string>& classesToRegister, JNIEnv* env) {
+
+ for (const string& className : classesToRegister) {
+ if (jniRegMap.at(className).mProc(env) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static vector<string> parseCsv(const string& csvString) {
+ vector<string> result;
+ istringstream stream(csvString);
+ string segment;
+ while(getline(stream, segment, ','))
+ {
+ result.push_back(segment);
+ }
+ return result;
+}
+
+static vector<string> parseCsv(JNIEnv* env, jstring csvJString) {
+ const char* charArray = env->GetStringUTFChars(csvJString, 0);
+ string csvString(charArray);
+ vector<string> result = parseCsv(csvString);
+ env->ReleaseStringUTFChars(csvJString, charArray);
+ return result;
+}
+
+} // namespace android
+
+using namespace android;
+
+void init_android_graphics() {
+ SkGraphics::Init();
+}
+
+int register_android_graphics_classes(JNIEnv *env) {
+ JavaVM* vm = nullptr;
+ env->GetJavaVM(&vm);
+ GraphicsJNI::setJavaVM(vm);
+
+ // Configuration is stored as java System properties.
+ // Get a reference to System.getProperty
+ jclass system = FindClassOrDie(env, "java/lang/System");
+ jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+
+ // Get the names of classes that need to register their native methods
+ auto nativesClassesJString =
+ (jstring) env->CallStaticObjectMethod(system,
+ getPropertyMethod, env->NewStringUTF("native_classes"),
+ env->NewStringUTF(""));
+ vector<string> classesToRegister = parseCsv(env, nativesClassesJString);
+
+ if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
+ return JNI_ERR;
+ }
+
+ return 0;
+}
+
+void zygote_preload_graphics() { }
diff --git a/core/jni/android/graphics/apex/TypeCast.h b/libs/hwui/apex/TypeCast.h
index 96721d007951..96721d007951 100644
--- a/core/jni/android/graphics/apex/TypeCast.h
+++ b/libs/hwui/apex/TypeCast.h
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp
index decd19071944..b56a619b00aa 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/libs/hwui/apex/android_bitmap.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "Bitmap"
#include <log/log.h>
diff --git a/core/jni/android/graphics/apex/android_canvas.cpp b/libs/hwui/apex/android_canvas.cpp
index 2a939efed9bb..2a939efed9bb 100644
--- a/core/jni/android/graphics/apex/android_canvas.cpp
+++ b/libs/hwui/apex/android_canvas.cpp
diff --git a/core/jni/android/graphics/apex/android_matrix.cpp b/libs/hwui/apex/android_matrix.cpp
index 309360d9b0b3..693b22b62663 100644
--- a/core/jni/android/graphics/apex/android_matrix.cpp
+++ b/libs/hwui/apex/android_matrix.cpp
@@ -15,7 +15,7 @@
*/
#include "android/graphics/matrix.h"
-#include "Matrix.h"
+#include "android_graphics_Matrix.h"
bool AMatrix_getContents(JNIEnv* env, jobject matrixObj, float values[9]) {
static_assert(SkMatrix::kMScaleX == 0, "SkMatrix unexpected index");
diff --git a/core/jni/android/graphics/apex/android_paint.cpp b/libs/hwui/apex/android_paint.cpp
index 70bd085343ce..70bd085343ce 100644
--- a/core/jni/android/graphics/apex/android_paint.cpp
+++ b/libs/hwui/apex/android_paint.cpp
diff --git a/core/jni/android/graphics/apex/android_region.cpp b/libs/hwui/apex/android_region.cpp
index 2030e7e69861..2030e7e69861 100644
--- a/core/jni/android/graphics/apex/android_region.cpp
+++ b/libs/hwui/apex/android_region.cpp
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/libs/hwui/apex/include/android/graphics/bitmap.h
index 45fec2ab7b43..8c4b439d2a2b 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/libs/hwui/apex/include/android/graphics/bitmap.h
@@ -18,6 +18,7 @@
#include <android/bitmap.h>
#include <android/data_space.h>
+#include <cutils/compiler.h>
#include <jni.h>
#include <sys/cdefs.h>
@@ -37,31 +38,31 @@ typedef struct ABitmap ABitmap;
* NOTE: This API does not need to remain as an APEX API if/when we pull libjnigraphics into the
* UI module.
*/
-AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj);
+ANDROID_API AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj);
/**
*
* @return ptr to an opaque handle to the native bitmap or null if the java bitmap has been recycled
* or does not exist.
*/
-ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj);
+ANDROID_API ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj);
-ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat);
+ANDROID_API ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat);
-void ABitmap_acquireRef(ABitmap* bitmap);
-void ABitmap_releaseRef(ABitmap* bitmap);
+ANDROID_API void ABitmap_acquireRef(ABitmap* bitmap);
+ANDROID_API void ABitmap_releaseRef(ABitmap* bitmap);
-AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap);
-ADataSpace ABitmap_getDataSpace(ABitmap* bitmap);
+ANDROID_API AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap);
+ANDROID_API ADataSpace ABitmap_getDataSpace(ABitmap* bitmap);
-void* ABitmap_getPixels(ABitmap* bitmap);
-void ABitmap_notifyPixelsChanged(ABitmap* bitmap);
+ANDROID_API void* ABitmap_getPixels(ABitmap* bitmap);
+ANDROID_API void ABitmap_notifyPixelsChanged(ABitmap* bitmap);
-AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj);
-jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
+ANDROID_API AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj);
+ANDROID_API jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
// NDK access
-int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
+ANDROID_API int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat format, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc);
/**
@@ -75,7 +76,7 @@ int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const
* a reference on the buffer, and the client must call
* AHardwareBuffer_release when finished with it.
*/
-AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmap);
+ANDROID_API AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmap);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/canvas.h b/libs/hwui/apex/include/android/graphics/canvas.h
index 6fd6b0693b37..a0cecc04a7e5 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/canvas.h
+++ b/libs/hwui/apex/include/android/graphics/canvas.h
@@ -20,6 +20,7 @@
#include <android/graphics/paint.h>
#include <android/native_window.h>
#include <android/rect.h>
+#include <cutils/compiler.h>
#include <jni.h>
__BEGIN_DECLS
@@ -30,24 +31,24 @@ __BEGIN_DECLS
typedef struct ACanvas ACanvas;
// One of AHardwareBuffer_Format.
-bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat);
+ANDROID_API bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat);
/**
* Returns a native handle to a Java android.graphics.Canvas
*
* @return ACanvas* that is only valid for the life of the jobject.
*/
-ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas);
+ANDROID_API ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas);
/**
* Creates a canvas that wraps the buffer
*
* @param buffer is a required param. If no buffer is provided a nullptr will be returned.
*/
-ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
+ANDROID_API ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
int32_t /*android_dataspace_t*/ dataspace);
-void ACanvas_destroyCanvas(ACanvas* canvas);
+ANDROID_API void ACanvas_destroyCanvas(ACanvas* canvas);
/**
* Updates the canvas to render into the pixels in the provided buffer
@@ -60,7 +61,7 @@ void ACanvas_destroyCanvas(ACanvas* canvas);
* method will behave as if nullptr were passed as the input buffer and the previous buffer
* will still be released.
*/
-bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
+ANDROID_API bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
int32_t /*android_dataspace_t*/ dataspace);
/**
@@ -68,21 +69,21 @@ bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
*
* @param clipRect required
*/
-void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
+ANDROID_API void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
/**
* Clips operations on the canvas to the difference of the current clip and the provided clipRect.
*
* @param clipRect required
*/
-void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
+ANDROID_API void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
/**
*
* @param rect required
* @param paint required
*/
-void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint);
+ANDROID_API void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint);
/**
*
@@ -91,7 +92,7 @@ void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint);
* @param top
* @param paint
*/
-void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top,
+ANDROID_API void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top,
const APaint* paint);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h b/libs/hwui/apex/include/android/graphics/jni_runtime.h
index 872a9497ab90..487383ed50d5 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h
+++ b/libs/hwui/apex/include/android/graphics/jni_runtime.h
@@ -16,15 +16,18 @@
#ifndef ANDROID_GRAPHICS_JNI_RUNTIME_H
#define ANDROID_GRAPHICS_JNI_RUNTIME_H
+#include <cutils/compiler.h>
#include <jni.h>
__BEGIN_DECLS
-void init_android_graphics();
+ANDROID_API void init_android_graphics();
-int register_android_graphics_classes(JNIEnv* env);
+ANDROID_API int register_android_graphics_classes(JNIEnv* env);
-void zygote_preload_graphics();
+ANDROID_API int register_android_graphics_GraphicsStatsService(JNIEnv* env);
+
+ANDROID_API void zygote_preload_graphics();
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/matrix.h b/libs/hwui/apex/include/android/graphics/matrix.h
index 4039cd1b8f74..987ad13f7635 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/matrix.h
+++ b/libs/hwui/apex/include/android/graphics/matrix.h
@@ -18,6 +18,7 @@
#define ANDROID_GRAPHICS_MATRIX_H
#include <jni.h>
+#include <cutils/compiler.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -31,7 +32,7 @@ __BEGIN_DECLS
* @return true if the values param was populated and false otherwise.
*/
-bool AMatrix_getContents(JNIEnv* env, jobject matrixObj, float values[9]);
+ANDROID_API bool AMatrix_getContents(JNIEnv* env, jobject matrixObj, float values[9]);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/paint.h b/libs/hwui/apex/include/android/graphics/paint.h
index 5895e006bf93..058db8d37619 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/paint.h
+++ b/libs/hwui/apex/include/android/graphics/paint.h
@@ -16,6 +16,7 @@
#ifndef ANDROID_GRAPHICS_PAINT_H
#define ANDROID_GRAPHICS_PAINT_H
+#include <cutils/compiler.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -35,11 +36,11 @@ enum ABlendMode {
ABLEND_MODE_SRC = 2,
};
-APaint* APaint_createPaint();
+ANDROID_API APaint* APaint_createPaint();
-void APaint_destroyPaint(APaint* paint);
+ANDROID_API void APaint_destroyPaint(APaint* paint);
-void APaint_setBlendMode(APaint* paint, ABlendMode blendMode);
+ANDROID_API void APaint_setBlendMode(APaint* paint, ABlendMode blendMode);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/region.h b/libs/hwui/apex/include/android/graphics/region.h
index 961067a8e2db..0756d6dd63f6 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/region.h
+++ b/libs/hwui/apex/include/android/graphics/region.h
@@ -16,6 +16,7 @@
#ifndef ANDROID_GRAPHICS_REGION_H
#define ANDROID_GRAPHICS_REGION_H
+#include <cutils/compiler.h>
#include <android/rect.h>
#include <sys/cdefs.h>
#include <jni.h>
@@ -35,19 +36,19 @@ typedef struct ARegionIterator ARegionIterator;
* @return ARegionIterator that must be closed and must not live longer than the life
* of the jobject. It returns nullptr if the region is not a valid object.
*/
-ARegionIterator* ARegionIterator_acquireIterator(JNIEnv* env, jobject region);
+ANDROID_API ARegionIterator* ARegionIterator_acquireIterator(JNIEnv* env, jobject region);
-void ARegionIterator_releaseIterator(ARegionIterator* iterator);
+ANDROID_API void ARegionIterator_releaseIterator(ARegionIterator* iterator);
-bool ARegionIterator_isComplex(ARegionIterator* iterator);
+ANDROID_API bool ARegionIterator_isComplex(ARegionIterator* iterator);
-bool ARegionIterator_isDone(ARegionIterator* iterator);
+ANDROID_API bool ARegionIterator_isDone(ARegionIterator* iterator);
-void ARegionIterator_next(ARegionIterator* iterator);
+ANDROID_API void ARegionIterator_next(ARegionIterator* iterator);
-ARect ARegionIterator_getRect(ARegionIterator* iterator);
+ANDROID_API ARect ARegionIterator_getRect(ARegionIterator* iterator);
-ARect ARegionIterator_getTotalBounds(ARegionIterator* iterator);
+ANDROID_API ARect ARegionIterator_getTotalBounds(ARegionIterator* iterator);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h b/libs/hwui/apex/include/android/graphics/renderthread.h
index 0a790af731a9..50280a6dd1fb 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
+++ b/libs/hwui/apex/include/android/graphics/renderthread.h
@@ -16,6 +16,7 @@
#ifndef ANDROID_GRAPHICS_RENDERTHREAD_H
#define ANDROID_GRAPHICS_RENDERTHREAD_H
+#include <cutils/compiler.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -26,7 +27,7 @@ __BEGIN_DECLS
* function requires a valid fd, but does not persist or assume ownership of the fd
* outside the scope of this function.
*/
-void ARenderThread_dumpGraphicsMemory(int fd);
+ANDROID_API void ARenderThread_dumpGraphicsMemory(int fd);
__END_DECLS
diff --git a/core/jni/android/graphics/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 35c997d80b61..a114e2f42157 100644
--- a/core/jni/android/graphics/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -21,9 +21,11 @@
#include <sys/cdefs.h>
#include <EGL/egl.h>
+#include <GraphicsJNI.h>
#include <Properties.h>
#include <SkGraphics.h>
+#undef LOG_TAG
#define LOG_TAG "AndroidGraphicsJNI"
extern int register_android_graphics_Bitmap(JNIEnv*);
@@ -59,7 +61,6 @@ extern int register_android_graphics_Path(JNIEnv* env);
extern int register_android_graphics_PathMeasure(JNIEnv* env);
extern int register_android_graphics_Picture(JNIEnv*);
extern int register_android_graphics_Region(JNIEnv* env);
-extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
@@ -122,7 +123,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Picture),
REG_JNI(register_android_graphics_Region),
REG_JNI(register_android_graphics_Shader),
- REG_JNI(register_android_graphics_SurfaceTexture),
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory),
@@ -151,6 +151,10 @@ void init_android_graphics() {
}
int register_android_graphics_classes(JNIEnv *env) {
+ JavaVM* vm = nullptr;
+ env->GetJavaVM(&vm);
+ GraphicsJNI::setJavaVM(vm);
+
for (size_t i = 0; i < NELEM(android::gRegJNI); i++) {
if (android::gRegJNI[i].mProc(env) < 0) {
#ifndef NDEBUG
diff --git a/core/jni/android/graphics/apex/renderthread.cpp b/libs/hwui/apex/renderthread.cpp
index 5d26afe7a2ab..5d26afe7a2ab 100644
--- a/core/jni/android/graphics/apex/renderthread.cpp
+++ b/libs/hwui/apex/renderthread.cpp
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 914c04645289..56d951cdb338 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -150,11 +150,7 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorS
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
-
- // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
- const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
- const size_t rowBytes = info.bytesPerPixel() * bufferStride;
- return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
+ return createFrom(hardwareBuffer, info, bufferDesc, palette);
}
sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
@@ -164,8 +160,14 @@ sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType co
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
colorType, alphaType, colorSpace);
+ return createFrom(hardwareBuffer, info, bufferDesc, palette);
+}
- const size_t rowBytes = info.bytesPerPixel() * bufferDesc.stride;
+sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+ const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
+ // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
+ const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
+ const size_t rowBytes = info.bytesPerPixel() * bufferStride;
return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
}
#endif
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3bfb7800f735..b8b59947a57b 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -169,6 +169,12 @@ private:
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
BitmapPalette palette);
+
+ // Common code for the two public facing createFrom(AHardwareBuffer*, ...)
+ // methods.
+ // bufferDesc is only used to compute rowBytes.
+ static sk_sp<Bitmap> createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
+ const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette);
#endif
virtual ~Bitmap();
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index 6c2a5a3f3fcc..055075d0c42a 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -17,7 +17,6 @@
#include "GraphicsJNI.h"
#include "ImageDecoder.h"
#include "Utils.h"
-#include "core_jni_helpers.h"
#include <SkAndroidCodec.h>
#include <SkAnimatedImage.h>
diff --git a/core/jni/android/graphics/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 130322aaaa45..ba669053ed63 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -1,3 +1,4 @@
+#undef LOG_TAG
#define LOG_TAG "Bitmap"
#include "Bitmap.h"
@@ -11,7 +12,6 @@
#include "SkStream.h"
#include "SkWebpEncoder.h"
-#include "android_os_Parcel.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include <hwui/Paint.h>
@@ -19,15 +19,12 @@
#include <utils/Color.h>
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
-#include <android_runtime/android_graphics_GraphicBuffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
#include <binder/Parcel.h>
#include <dlfcn.h>
#include <renderthread/RenderProxy.h>
#endif
-#include "core_jni_helpers.h"
-
-#include <jni.h>
#include <string.h>
#include <memory>
#include <string>
@@ -570,6 +567,25 @@ static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
///////////////////////////////////////////////////////////////////////////////
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+static struct parcel_offsets_t
+{
+ jclass clazz;
+ jfieldID mNativePtr;
+} gParcelOffsets;
+
+static Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) {
+ if (obj) {
+ Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
+ if (p != NULL) {
+ return p;
+ }
+ jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
+ }
+ return NULL;
+}
+#endif
+
// This is the maximum possible size because the SkColorSpace must be
// representable (and therefore serializable) using a matrix and numerical
// transfer function. If we allow more color space representations in the
@@ -583,7 +599,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
return NULL;
}
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
+ android::Parcel* p = parcelForJavaObject(env, parcel);
const SkColorType colorType = (SkColorType)p->readInt32();
const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
@@ -706,7 +722,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
return JNI_FALSE;
}
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
+ android::Parcel* p = parcelForJavaObject(env, parcel);
SkBitmap bitmap;
auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
@@ -1050,19 +1066,6 @@ static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject har
#endif
}
-static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
-#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
- LocalScopedBitmap bitmapHandle(bitmapPtr);
- LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
- "Hardware config is only supported config in Bitmap_getGraphicBuffer");
-
- Bitmap& bitmap = bitmapHandle->bitmap();
- return android_graphics_GraphicBuffer_createFromAHardwareBuffer(env, bitmap.hardwareBuffer());
-#else
- return NULL;
-#endif
-}
-
static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
LocalScopedBitmap bitmapHandle(bitmapPtr);
@@ -1140,8 +1143,6 @@ static const JNINativeMethod gBitmapMethods[] = {
(void*)Bitmap_copyPreserveInternalConfig },
{ "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
(void*) Bitmap_wrapHardwareBufferBitmap },
- { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
- (void*) Bitmap_createGraphicBufferHandle },
{ "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
(void*) Bitmap_getHardwareBuffer },
{ "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
@@ -1155,6 +1156,8 @@ static const JNINativeMethod gBitmapMethods[] = {
};
+const char* const kParcelPathName = "android/os/Parcel";
+
int register_android_graphics_Bitmap(JNIEnv* env)
{
gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
@@ -1162,7 +1165,7 @@ int register_android_graphics_Bitmap(JNIEnv* env)
gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
-#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
+#ifdef __ANDROID__ // Layoutlib does not support graphic buffer or parcel
void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
AHardwareBuffer_fromHardwareBuffer =
(AHB_from_HB)dlsym(handle_, "AHardwareBuffer_fromHardwareBuffer");
@@ -1172,6 +1175,9 @@ int register_android_graphics_Bitmap(JNIEnv* env)
AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
" Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
+
+ gParcelOffsets.clazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kParcelPathName));
+ gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, gParcelOffsets.clazz, "mNativePtr", "J");
#endif
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
diff --git a/core/jni/android/graphics/Bitmap.h b/libs/hwui/jni/Bitmap.h
index 73eca3aa8ef8..73eca3aa8ef8 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/libs/hwui/jni/Bitmap.h
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index adedffdd731c..d4e27d812500 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -1,8 +1,10 @@
+#undef LOG_TAG
#define LOG_TAG "BitmapFactory"
#include "BitmapFactory.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "GraphicsJNI.h"
+#include "MimeType.h"
#include "NinePatchPeeker.h"
#include "SkAndroidCodec.h"
#include "SkBRDAllocator.h"
@@ -12,17 +14,15 @@
#include "SkStream.h"
#include "SkUtils.h"
#include "Utils.h"
-#include "core_jni_helpers.h"
#include <HardwareBitmapUploader.h>
#include <nativehelper/JNIHelp.h>
#include <androidfw/Asset.h>
#include <androidfw/ResourceTypes.h>
#include <cutils/compiler.h>
+#include <fcntl.h>
#include <memory>
-#include <netinet/in.h>
#include <stdio.h>
-#include <sys/mman.h>
#include <sys/stat.h>
jfieldID gOptions_justBoundsFieldID;
@@ -521,7 +521,9 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA
static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
jobject padding, jobject bitmapFactoryOptions, jlong inBitmapHandle, jlong colorSpaceHandle) {
-
+#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
+ return nullObjectReturn("Not supported on Windows");
+#else
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -568,6 +570,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, inBitmapHandle,
colorSpaceHandle);
+#endif
}
static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
diff --git a/core/jni/android/graphics/BitmapFactory.h b/libs/hwui/jni/BitmapFactory.h
index 45bffc44967d..45bffc44967d 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/libs/hwui/jni/BitmapFactory.h
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index 06b4ff849097..712351382d97 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "BitmapRegionDecoder"
#include "BitmapFactory.h"
@@ -27,12 +28,8 @@
#include "SkData.h"
#include "SkStream.h"
-#include "core_jni_helpers.h"
-
#include <HardwareBitmapUploader.h>
-#include <nativehelper/JNIHelp.h>
#include <androidfw/Asset.h>
-#include <jni.h>
#include <sys/stat.h>
#include <memory>
diff --git a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp
index d443fd8cdf14..db5f6f6c684f 100644
--- a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
+++ b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp
@@ -1,7 +1,6 @@
#include "ByteBufferStreamAdaptor.h"
-#include "core_jni_helpers.h"
+#include "GraphicsJNI.h"
#include "Utils.h"
-#include <jni.h>
#include <SkStream.h>
diff --git a/core/jni/android/graphics/ByteBufferStreamAdaptor.h b/libs/hwui/jni/ByteBufferStreamAdaptor.h
index 367a48fad9b9..367a48fad9b9 100644
--- a/core/jni/android/graphics/ByteBufferStreamAdaptor.h
+++ b/libs/hwui/jni/ByteBufferStreamAdaptor.h
diff --git a/core/jni/android/graphics/Camera.cpp b/libs/hwui/jni/Camera.cpp
index da954972ab57..a5e1adf26861 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/libs/hwui/jni/Camera.cpp
@@ -1,6 +1,3 @@
-#include "jni.h"
-#include "core_jni_helpers.h"
-
#include "SkCamera.h"
#include "GraphicsJNI.h"
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/libs/hwui/jni/CanvasProperty.cpp
index c841d6a5125a..684ee23b9fca 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/libs/hwui/jni/CanvasProperty.cpp
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include <core_jni_helpers.h>
#include <hwui/Paint.h>
#include <utils/RefBase.h>
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp
index 164d35f46a47..cef21f91f3c1 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/libs/hwui/jni/ColorFilter.cpp
@@ -15,9 +15,7 @@
** limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
index 39483b55992b..39483b55992b 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h
index fccd4717c4b7..849418da01a1 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.h
@@ -1,7 +1,6 @@
#ifndef _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
#define _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
-//#include <android_runtime/AndroidRuntime.h>
#include "jni.h"
class SkMemoryStream;
diff --git a/core/jni/android/graphics/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index 0fd9cc7e9989..a2fef1e19328 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -14,11 +14,9 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "Minikin"
-#include <nativehelper/JNIHelp.h>
-#include <core_jni_helpers.h>
-
#include "SkData.h"
#include "SkFontMgr.h"
#include "SkRefCnt.h"
@@ -26,7 +24,6 @@
#include "GraphicsJNI.h"
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
-#include <android_runtime/AndroidRuntime.h>
#include "Utils.h"
#include "FontUtils.h"
@@ -144,15 +141,11 @@ static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, in
}
static void release_global_ref(const void* /*data*/, void* context) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = GraphicsJNI::getJNIEnv();
bool needToAttach = (env == NULL);
if (needToAttach) {
- JavaVMAttachArgs args;
- args.version = JNI_VERSION_1_4;
- args.name = "release_font_data";
- args.group = NULL;
- jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
- if (result != JNI_OK) {
+ env = GraphicsJNI::attachJNIEnv("release_font_data");
+ if (env == nullptr) {
ALOGE("failed to attach to thread to release global ref.");
return;
}
@@ -162,7 +155,7 @@ static void release_global_ref(const void* /*data*/, void* context) {
env->DeleteGlobalRef(obj);
if (needToAttach) {
- AndroidRuntime::getJavaVM()->DetachCurrentThread();
+ GraphicsJNI::detachJNIEnv();
}
}
diff --git a/core/jni/android/graphics/FontUtils.cpp b/libs/hwui/jni/FontUtils.cpp
index 0cf61b9ade89..654c5fdf6528 100644
--- a/core/jni/android/graphics/FontUtils.cpp
+++ b/libs/hwui/jni/FontUtils.cpp
@@ -16,8 +16,7 @@
#include "FontUtils.h"
-#include <nativehelper/JNIHelp.h>
-#include <core_jni_helpers.h>
+#include "graphics_jni_helpers.h"
namespace android {
namespace {
diff --git a/core/jni/android/graphics/FontUtils.h b/libs/hwui/jni/FontUtils.h
index b36b4e60e33a..b36b4e60e33a 100644
--- a/core/jni/android/graphics/FontUtils.h
+++ b/libs/hwui/jni/FontUtils.h
diff --git a/core/jni/android/graphics/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index f84a4bd09073..f84a4bd09073 100644
--- a/core/jni/android/graphics/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
diff --git a/core/jni/android/graphics/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index 38fb8bdc1f7a..f76ecb4c9c8a 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -1,22 +1,55 @@
+#undef LOG_TAG
#define LOG_TAG "GraphicsJNI"
+#include <assert.h>
#include <unistd.h>
-#include <sys/mman.h>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include "SkCanvas.h"
#include "SkMath.h"
#include "SkRegion.h"
-#include <android_runtime/AndroidRuntime.h>
#include <cutils/ashmem.h>
#include <hwui/Canvas.h>
using namespace android;
+/*static*/ JavaVM* GraphicsJNI::mJavaVM = nullptr;
+
+void GraphicsJNI::setJavaVM(JavaVM* javaVM) {
+ mJavaVM = javaVM;
+}
+
+/** return a pointer to the JNIEnv for this thread */
+JNIEnv* GraphicsJNI::getJNIEnv() {
+ assert(mJavaVM != nullptr);
+ JNIEnv* env;
+ if (mJavaVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ return nullptr;
+ }
+ return env;
+}
+
+/** create a JNIEnv* for this thread or assert if one already exists */
+JNIEnv* GraphicsJNI::attachJNIEnv(const char* envName) {
+ assert(getJNIEnv() == nullptr);
+ JNIEnv* env = nullptr;
+ JavaVMAttachArgs args = { JNI_VERSION_1_4, envName, NULL };
+ int result = mJavaVM->AttachCurrentThread(&env, (void*) &args);
+ if (result != JNI_OK) {
+ ALOGE("thread attach failed: %#x", result);
+ }
+ return env;
+}
+
+/** detach the current thread from the JavaVM */
+void GraphicsJNI::detachJNIEnv() {
+ assert(mJavaVM != nullptr);
+ mJavaVM->DetachCurrentThread();
+}
+
void doThrowNPE(JNIEnv* env) {
jniThrowNullPointerException(env, NULL);
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index 1e497654f18d..b58a740a4c27 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -1,6 +1,8 @@
#ifndef _ANDROID_GRAPHICS_GRAPHICS_JNI_H_
#define _ANDROID_GRAPHICS_GRAPHICS_JNI_H_
+#include <cutils/compiler.h>
+
#include "Bitmap.h"
#include "SkBitmap.h"
#include "SkBRDAllocator.h"
@@ -10,10 +12,11 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkColorSpace.h"
-#include <jni.h>
#include <hwui/Canvas.h>
#include <hwui/Bitmap.h>
+#include "graphics_jni_helpers.h"
+
class SkBitmapRegionDecoder;
class SkCanvas;
@@ -39,6 +42,20 @@ public:
kLastEnum_LegacyBitmapConfig = kHardware_LegacyBitmapConfig
};
+ static void setJavaVM(JavaVM* javaVM);
+
+ /** returns a pointer to the JavaVM provided when we initialized the module */
+ static JavaVM* getJavaVM() { return mJavaVM; }
+
+ /** return a pointer to the JNIEnv for this thread */
+ static JNIEnv* getJNIEnv();
+
+ /** create a JNIEnv* for this thread or assert if one already exists */
+ static JNIEnv* attachJNIEnv(const char* envName);
+
+ /** detach the current thread from the JavaVM */
+ static void detachJNIEnv();
+
// returns true if an exception is set (and dumps it out to the Log)
static bool hasException(JNIEnv*);
@@ -60,7 +77,7 @@ public:
static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point);
static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
- static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
+ ANDROID_API static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes,
bool* isHardware);
@@ -131,6 +148,10 @@ public:
* above.
*/
static SkColor4f convertColorLong(jlong color);
+
+private:
+ /* JNI JavaVM pointer */
+ static JavaVM* mJavaVM;
};
class HeapAllocator : public SkBRDAllocator {
diff --git a/core/jni/android/graphics/GraphicsStatsService.cpp b/libs/hwui/jni/GraphicsStatsService.cpp
index ef0aacc4d9ec..6076552fc094 100644
--- a/core/jni/android/graphics/GraphicsStatsService.cpp
+++ b/libs/hwui/jni/GraphicsStatsService.cpp
@@ -14,19 +14,20 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "GraphicsStatsService"
#include <JankTracker.h>
-#include <jni.h>
#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
#include <service/GraphicsStatsService.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
-#include "core_jni_helpers.h"
+
+#include "android/graphics/jni_runtime.h"
+#include "GraphicsJNI.h"
namespace android {
@@ -115,7 +116,7 @@ static jobject gGraphicsStatsServiceObject = nullptr;
static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
static JNIEnv* getJNIEnv() {
- JavaVM* vm = AndroidRuntime::getJavaVM();
+ JavaVM* vm = GraphicsJNI::getJavaVM();
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
@@ -172,6 +173,9 @@ static void nativeDestructor(JNIEnv* env, jobject javaObject) {
gGraphicsStatsServiceObject = nullptr;
}
+} // namespace android
+using namespace android;
+
static const JNINativeMethod sMethods[] =
{{"nGetAshmemSize", "()I", (void*)getAshmemSize},
{"nCreateDump", "(IZ)J", (void*)createDump},
@@ -191,5 +195,3 @@ int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
NELEM(sMethods));
}
-
-} // namespace android
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index e17e057d75c7..b6b378539bd0 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -22,7 +22,6 @@
#include "ImageDecoder.h"
#include "NinePatchPeeker.h"
#include "Utils.h"
-#include "core_jni_helpers.h"
#include <hwui/Bitmap.h>
#include <hwui/ImageDecoder.h>
@@ -34,7 +33,7 @@
#include <SkStream.h>
#include <androidfw/Asset.h>
-#include <jni.h>
+#include <fcntl.h>
#include <sys/stat.h>
using namespace android;
@@ -154,6 +153,9 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
jobject fileDescriptor, jboolean preferAnimation, jobject source) {
+#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
+ return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
+#else
int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
struct stat fdStat;
@@ -172,6 +174,7 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
return native_create(env, std::move(fileStream), source, preferAnimation);
+#endif
}
static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
diff --git a/core/jni/android/graphics/ImageDecoder.h b/libs/hwui/jni/ImageDecoder.h
index 8a7fa79503ba..8a7fa79503ba 100644
--- a/core/jni/android/graphics/ImageDecoder.h
+++ b/libs/hwui/jni/ImageDecoder.h
diff --git a/core/jni/android/graphics/Interpolator.cpp b/libs/hwui/jni/Interpolator.cpp
index fa28359281db..146d634a297c 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/libs/hwui/jni/Interpolator.cpp
@@ -1,8 +1,5 @@
#include "GraphicsJNI.h"
#include "SkInterpolator.h"
-#include "core_jni_helpers.h"
-
-#include <jni.h>
static jlong Interpolator_constructor(JNIEnv* env, jobject clazz, jint valueCount, jint frameCount)
{
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 33d346f5d379..5383032e0f77 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -4,10 +4,6 @@
#include "SkBlurMaskFilter.h"
#include "SkTableMaskFilter.h"
-#include "core_jni_helpers.h"
-
-#include <jni.h>
-
static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
if (NULL == ptr) {
doThrowIAE(env);
diff --git a/core/jni/android/graphics/MimeType.h b/libs/hwui/jni/MimeType.h
index 38a579c595e4..fdd510cfeb79 100644
--- a/core/jni/android/graphics/MimeType.h
+++ b/libs/hwui/jni/MimeType.h
@@ -16,6 +16,7 @@
#pragma once
+#include <cutils/compiler.h>
#include "SkEncodedImageFormat.h"
-const char* getMimeType(SkEncodedImageFormat);
+ANDROID_API const char* getMimeType(SkEncodedImageFormat);
diff --git a/core/jni/android/graphics/Movie.cpp b/libs/hwui/jni/Movie.cpp
index 4c10a85c8257..ede0ca8cda5b 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/libs/hwui/jni/Movie.cpp
@@ -6,13 +6,11 @@
#include "SkStream.h"
#include "SkUtils.h"
#include "Utils.h"
-#include "core_jni_helpers.h"
#include <androidfw/Asset.h>
#include <androidfw/ResourceTypes.h>
#include <hwui/Canvas.h>
#include <hwui/Paint.h>
-#include <jni.h>
#include <netinet/in.h>
static jclass gMovie_class;
diff --git a/core/jni/android/graphics/Movie.h b/libs/hwui/jni/Movie.h
index 736890d5215e..736890d5215e 100644
--- a/core/jni/android/graphics/Movie.h
+++ b/libs/hwui/jni/Movie.h
diff --git a/core/jni/android/graphics/MovieImpl.cpp b/libs/hwui/jni/MovieImpl.cpp
index ae9e04e617b0..ae9e04e617b0 100644
--- a/core/jni/android/graphics/MovieImpl.cpp
+++ b/libs/hwui/jni/MovieImpl.cpp
diff --git a/core/jni/android/graphics/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index 15f951688d43..6942017d5f27 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -15,6 +15,7 @@
** limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "9patch"
#define LOG_NDEBUG 1
@@ -30,9 +31,6 @@
#include "NinePatchPeeker.h"
#include "NinePatchUtils.h"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
jclass gInsetStruct_class;
jmethodID gInsetStruct_constructorMethodID;
diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/libs/hwui/jni/NinePatchPeeker.cpp
index 9171fc687276..9171fc687276 100644
--- a/core/jni/android/graphics/NinePatchPeeker.cpp
+++ b/libs/hwui/jni/NinePatchPeeker.cpp
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/libs/hwui/jni/NinePatchPeeker.h
index e4e58dda4783..e4e58dda4783 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/libs/hwui/jni/NinePatchPeeker.h
diff --git a/core/jni/android/graphics/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 8e1bc8489baa..df8635a8fe5a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -15,13 +15,12 @@
** limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "Paint"
#include <utils/Log.h>
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include <nativehelper/ScopedStringChars.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
diff --git a/core/jni/android/graphics/PaintFilter.cpp b/libs/hwui/jni/PaintFilter.cpp
index 4fe9140572d3..ec115b4e141c 100644
--- a/core/jni/android/graphics/PaintFilter.cpp
+++ b/libs/hwui/jni/PaintFilter.cpp
@@ -15,11 +15,7 @@
** limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include "core_jni_helpers.h"
#include "hwui/Paint.h"
#include "hwui/PaintFilter.h"
diff --git a/core/jni/android/graphics/Path.cpp b/libs/hwui/jni/Path.cpp
index 481445258e3c..d67bcf221681 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/libs/hwui/jni/Path.cpp
@@ -20,9 +20,7 @@
// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
// or one of the auxilary file specifications in device/tools/gluemaker.
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include "SkPath.h"
#include "SkPathOps.h"
diff --git a/core/jni/android/graphics/PathEffect.cpp b/libs/hwui/jni/PathEffect.cpp
index a4992de72ff6..f99bef7b7d58 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/libs/hwui/jni/PathEffect.cpp
@@ -4,9 +4,6 @@
#include "SkDashPathEffect.h"
#include "SkDiscretePathEffect.h"
#include "SkPathEffect.h"
-#include "core_jni_helpers.h"
-
-#include <jni.h>
class SkPathEffectGlue {
public:
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/libs/hwui/jni/PathMeasure.cpp
index 70e528d4be6f..acf893e9544c 100644
--- a/core/jni/android/graphics/PathMeasure.cpp
+++ b/libs/hwui/jni/PathMeasure.cpp
@@ -15,9 +15,7 @@
** limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include <core_jni_helpers.h>
#include "SkPathMeasure.h"
diff --git a/core/jni/android/graphics/Picture.cpp b/libs/hwui/jni/Picture.cpp
index d1b952130e88..d1b952130e88 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/libs/hwui/jni/Picture.cpp
diff --git a/core/jni/android/graphics/Picture.h b/libs/hwui/jni/Picture.h
index 536f651473a9..536f651473a9 100644
--- a/core/jni/android/graphics/Picture.h
+++ b/libs/hwui/jni/Picture.h
diff --git a/core/jni/android/graphics/Region.cpp b/libs/hwui/jni/Region.cpp
index 87662f713449..1e064b820591 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/libs/hwui/jni/Region.cpp
@@ -19,13 +19,10 @@
#include "GraphicsJNI.h"
#ifdef __ANDROID__ // Layoutlib does not support parcel
-#include <binder/Parcel.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_jni.h>
+#include <android/binder_parcel_utils.h>
#endif
-#include "android_os_Parcel.h"
-#include "android_util_Binder.h"
-
-#include <jni.h>
-#include <core_jni_helpers.h>
namespace android {
@@ -210,10 +207,11 @@ static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
return 0;
}
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
std::vector<int32_t> rects;
- p->readInt32Vector(&rects);
+
+ AParcel* p = AParcel_fromJavaParcel(env, parcel);
+ ndk::AParcel_readVector(p, &rects);
+ AParcel_delete(p);
if ((rects.size() % 4) != 0) {
return 0;
@@ -238,8 +236,6 @@ static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHan
return JNI_FALSE;
}
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
std::vector<int32_t> rects;
SkRegion::Iterator it(*region);
while (!it.done()) {
@@ -251,7 +247,10 @@ static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHan
it.next();
}
- p->writeInt32Vector(rects);
+ AParcel* p = AParcel_fromJavaParcel(env, parcel);
+ ndk::AParcel_writeVector(p, rects);
+ AParcel_delete(p);
+
return JNI_TRUE;
#else
return JNI_FALSE;
diff --git a/core/jni/android/graphics/RtlProperties.h b/libs/hwui/jni/RtlProperties.h
index 907dd59b6e68..907dd59b6e68 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/libs/hwui/jni/RtlProperties.h
diff --git a/core/jni/android/graphics/Shader.cpp b/libs/hwui/jni/Shader.cpp
index f5e2a5244416..0f6837640524 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -4,11 +4,8 @@
#include "SkImagePriv.h"
#include "SkShader.h"
#include "SkBlendMode.h"
-#include "core_jni_helpers.h"
#include "include/effects/SkRuntimeEffect.h"
-#include <jni.h>
-
#include <vector>
using namespace android::uirenderer;
diff --git a/core/jni/android/graphics/TEST_MAPPING b/libs/hwui/jni/TEST_MAPPING
index 10bd0ee906fd..10bd0ee906fd 100644
--- a/core/jni/android/graphics/TEST_MAPPING
+++ b/libs/hwui/jni/TEST_MAPPING
diff --git a/core/jni/android/graphics/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index 4ce56ba7444f..2a5f402a4fa6 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-#include "jni.h"
-#include "core_jni_helpers.h"
-
#include "FontUtils.h"
#include "GraphicsJNI.h"
#include <nativehelper/ScopedPrimitiveArray.h>
diff --git a/core/jni/android/graphics/Utils.cpp b/libs/hwui/jni/Utils.cpp
index 17c194d04f84..17c194d04f84 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/libs/hwui/jni/Utils.cpp
diff --git a/core/jni/android/graphics/Utils.h b/libs/hwui/jni/Utils.h
index 89255177ba2e..89255177ba2e 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/libs/hwui/jni/Utils.h
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 09adc824e520..689cf0bea741 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -4,9 +4,7 @@
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
-#include "core_jni_helpers.h"
-
-#include <jni.h>
+#include "graphics_jni_helpers.h"
YuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
// Only ImageFormat.NV21 and ImageFormat.YUY2 are supported
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index 7e7b935df276..7e7b935df276 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
diff --git a/core/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0ad3339ee05f..4aff3e544efa 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#ifdef __ANDROID_
#include <android/api-level.h>
diff --git a/core/jni/android_graphics_ColorSpace.cpp b/libs/hwui/jni/android_graphics_ColorSpace.cpp
index 7648fd021d18..232fd71a12b4 100644
--- a/core/jni/android_graphics_ColorSpace.cpp
+++ b/libs/hwui/jni/android_graphics_ColorSpace.cpp
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include "SkColor.h"
#include "SkColorSpace.h"
+#include "SkHalf.h"
using namespace android;
@@ -42,9 +41,13 @@ static skcms_Matrix3x3 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
///////////////////////////////////////////////////////////////////////////////
static float halfToFloat(uint16_t bits) {
- __fp16 h;
- memcpy(&h, &bits, 2);
- return (float)h;
+#ifdef __ANDROID__ // __fp16 is not defined on non-Android builds
+ __fp16 h;
+ memcpy(&h, &bits, 2);
+ return (float)h;
+#else
+ return SkHalfToFloat(bits);
+#endif
}
SkColor4f GraphicsJNI::convertColorLong(jlong color) {
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 9907da5a2e68..54822f1f07e2 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -14,13 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
-#include "jni.h"
#include "GraphicsJNI.h"
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
#ifdef __ANDROID__ // Layoutlib does not support Looper and device properties
#include <utils/Looper.h>
#endif
@@ -38,8 +33,6 @@
#include <renderthread/RenderProxy.h>
#endif
-#include "core_jni_helpers.h"
-
namespace android {
using namespace uirenderer;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 93449ffeae1b..49c7fcd468e1 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "ThreadedRenderer"
#define ATRACE_TAG ATRACE_TAG_VIEW
@@ -43,8 +44,6 @@
#include <atomic>
#include "android_graphics_HardwareRendererObserver.h"
-#include "core_jni_helpers.h"
-#include "jni.h"
namespace android {
diff --git a/core/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
index 89b77b0b069a..5b3e65648981 100644
--- a/core/jni/android_graphics_HardwareRendererObserver.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp
@@ -16,7 +16,7 @@
#include "android_graphics_HardwareRendererObserver.h"
-#include "core_jni_helpers.h"
+#include "graphics_jni_helpers.h"
#include "nativehelper/jni_macros.h"
#include <array>
diff --git a/core/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
index 62111fd7d7a1..62111fd7d7a1 100644
--- a/core/jni/android_graphics_HardwareRendererObserver.h
+++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h
diff --git a/core/jni/android/graphics/Matrix.cpp b/libs/hwui/jni/android_graphics_Matrix.cpp
index 13369763e0cf..7338ef24cb58 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/libs/hwui/jni/android_graphics_Matrix.cpp
@@ -18,9 +18,6 @@
#include "GraphicsJNI.h"
#include "Matrix.h"
#include "SkMatrix.h"
-#include "core_jni_helpers.h"
-
-#include <jni.h>
namespace android {
diff --git a/core/jni/android/graphics/Matrix.h b/libs/hwui/jni/android_graphics_Matrix.h
index fe90d2ef945d..fe90d2ef945d 100644
--- a/core/jni/android/graphics/Matrix.h
+++ b/libs/hwui/jni/android_graphics_Matrix.h
diff --git a/core/jni/android_graphics_Picture.cpp b/libs/hwui/jni/android_graphics_Picture.cpp
index 1d085e5ccc49..403efb2ab9c9 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/libs/hwui/jni/android_graphics_Picture.cpp
@@ -19,12 +19,9 @@
#include "Picture.h"
#include "SkCanvas.h"
#include "SkStream.h"
-#include "core_jni_helpers.h"
-#include "nativehelper/jni_macros.h"
-
-#include <jni.h>
#include <array>
+#include "nativehelper/jni_macros.h"
namespace android {
diff --git a/core/jni/android_view_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index a8246c7d84b7..85c802b40459 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -14,12 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
#define ATRACE_TAG ATRACE_TAG_VIEW
-#include "jni.h"
#include "GraphicsJNI.h"
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
#include <Animator.h>
#include <DamageAccumulator.h>
@@ -32,8 +28,6 @@
#include <hwui/Paint.h>
#include <utils/TraceUtils.h>
-#include "core_jni_helpers.h"
-
namespace android {
using namespace uirenderer;
diff --git a/core/jni/android_view_TextureLayer.cpp b/libs/hwui/jni/android_graphics_TextureLayer.cpp
index 40f618025f99..bd20269d3751 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/libs/hwui/jni/android_graphics_TextureLayer.cpp
@@ -14,13 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-
#include <android/surface_texture_jni.h>
-#include "core_jni_helpers.h"
+#include "graphics_jni_helpers.h"
#include <hwui/Paint.h>
#include <SkMatrix.h>
diff --git a/core/jni/android_graphics_animation_NativeInterpolatorFactory.cpp b/libs/hwui/jni/android_graphics_animation_NativeInterpolatorFactory.cpp
index 2073ac2d24be..764eff9a04be 100644
--- a/core/jni/android_graphics_animation_NativeInterpolatorFactory.cpp
+++ b/libs/hwui/jni/android_graphics_animation_NativeInterpolatorFactory.cpp
@@ -16,12 +16,10 @@
#define LOG_TAG "OpenGLRenderer"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <Interpolator.h>
#include <cutils/log.h>
-#include "core_jni_helpers.h"
-#include <Interpolator.h>
+#include "graphics_jni_helpers.h"
namespace android {
diff --git a/core/jni/android_graphics_animation_RenderNodeAnimator.cpp b/libs/hwui/jni/android_graphics_animation_RenderNodeAnimator.cpp
index 878d4fc13f6d..c6d26f853c1d 100644
--- a/core/jni/android_graphics_animation_RenderNodeAnimator.cpp
+++ b/libs/hwui/jni/android_graphics_animation_RenderNodeAnimator.cpp
@@ -16,15 +16,11 @@
#define LOG_TAG "OpenGLRenderer"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-
#include <Animator.h>
#include <Interpolator.h>
#include <RenderProperties.h>
-#include "core_jni_helpers.h"
+#include "graphics_jni_helpers.h"
namespace android {
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index b6b53666e26e..b3121e7b0373 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
#include "android/log.h"
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include "Animator.h"
#include "Interpolator.h"
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
index 58a2379a6999..8a262969614e 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -15,8 +15,6 @@
*/
#include "GraphicsJNI.h"
-#include "jni.h"
-#include "core_jni_helpers.h"
#include "PathParser.h"
#include "VectorDrawable.h"
diff --git a/core/jni/android_nio_utils.cpp b/libs/hwui/jni/android_nio_utils.cpp
index 1e6d49e49b72..c2b09c1d15d7 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/libs/hwui/jni/android_nio_utils.cpp
@@ -16,7 +16,7 @@
#include "android_nio_utils.h"
-#include "core_jni_helpers.h"
+#include <nativehelper/JNIHelp.h>
namespace android {
diff --git a/core/jni/android_nio_utils.h b/libs/hwui/jni/android_nio_utils.h
index 4aaa0a78c276..4aaa0a78c276 100644
--- a/core/jni/android_nio_utils.h
+++ b/libs/hwui/jni/android_nio_utils.h
diff --git a/core/jni/android_util_PathParser.cpp b/libs/hwui/jni/android_util_PathParser.cpp
index 10efb95100ac..df5e9cd44ed0 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/libs/hwui/jni/android_util_PathParser.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
#include <PathParser.h>
@@ -22,7 +21,6 @@
#include <utils/VectorDrawableUtils.h>
#include <android/log.h>
-#include "core_jni_helpers.h"
namespace android {
diff --git a/core/jni/android/graphics/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index bfb9bae45f0c..5714cd1d0390 100644
--- a/core/jni/android/graphics/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -14,18 +14,15 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "Minikin"
-#include <nativehelper/JNIHelp.h>
-#include <core_jni_helpers.h>
-
#include "SkData.h"
#include "SkFontMgr.h"
#include "SkRefCnt.h"
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <nativehelper/ScopedUtfChars.h>
-#include <android_runtime/AndroidRuntime.h>
#include "Utils.h"
#include "FontUtils.h"
@@ -51,14 +48,11 @@ static void releaseFont(jlong font) {
}
static void release_global_ref(const void* /*data*/, void* context) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- if (env == nullptr) {
- JavaVMAttachArgs args;
- args.version = JNI_VERSION_1_4;
- args.name = "release_font_data";
- args.group = nullptr;
- jint result = AndroidRuntime::getJavaVM()->AttachCurrentThread(&env, &args);
- if (result != JNI_OK) {
+ JNIEnv* env = GraphicsJNI::getJNIEnv();
+ bool needToAttach = (env == nullptr);
+ if (needToAttach) {
+ env = GraphicsJNI::attachJNIEnv("release_font_data");
+ if (env == nullptr) {
ALOGE("failed to attach to thread to release global ref.");
return;
}
diff --git a/core/jni/android/graphics/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index b0d10c356a9b..df619d9f1406 100644
--- a/core/jni/android/graphics/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "Minikin"
-#include <nativehelper/JNIHelp.h>
+#include "graphics_jni_helpers.h"
#include <nativehelper/ScopedUtfChars.h>
-#include <core_jni_helpers.h>
#include "FontUtils.h"
diff --git a/libs/hwui/jni/graphics_jni_helpers.h b/libs/hwui/jni/graphics_jni_helpers.h
new file mode 100644
index 000000000000..b97cc6a10179
--- /dev/null
+++ b/libs/hwui/jni/graphics_jni_helpers.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#ifndef GRAPHICS_JNI_HELPERS
+#define GRAPHICS_JNI_HELPERS
+
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/scoped_local_ref.h>
+#include <nativehelper/scoped_utf_chars.h>
+#include <string>
+
+// Host targets (layoutlib) do not differentiate between regular and critical native methods,
+// and they need all the JNI methods to have JNIEnv* and jclass/jobject as their first two arguments.
+// The following macro allows to have those arguments when compiling for host while omitting them when
+// compiling for Android.
+#ifdef __ANDROID__
+#define CRITICAL_JNI_PARAMS
+#define CRITICAL_JNI_PARAMS_COMMA
+#else
+#define CRITICAL_JNI_PARAMS JNIEnv*, jclass
+#define CRITICAL_JNI_PARAMS_COMMA JNIEnv*, jclass,
+#endif
+
+namespace android {
+
+// Defines some helpful functions.
+
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+ jclass clazz = env->FindClass(class_name);
+ LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+ return clazz;
+}
+
+static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
+ const char* field_signature) {
+ jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ return res;
+}
+
+static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
+ const char* method_signature) {
+ jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s", method_name);
+ return res;
+}
+
+static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
+ const char* field_signature) {
+ jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+ return res;
+}
+
+static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
+ const char* method_signature) {
+ jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s", method_name);
+ return res;
+}
+
+template <typename T>
+static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
+ jobject res = env->NewGlobalRef(in);
+ LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference.");
+ return static_cast<T>(res);
+}
+
+static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
+ const JNINativeMethod* gMethods, int numMethods) {
+ int res = jniRegisterNativeMethods(env, className, gMethods, numMethods);
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+ return res;
+}
+
+/**
+ * Read the specified field from jobject, and convert to std::string.
+ * If the field cannot be obtained, return defaultValue.
+ */
+static inline std::string getStringField(JNIEnv* env, jobject obj, jfieldID fieldId,
+ const char* defaultValue) {
+ ScopedLocalRef<jstring> strObj(env, jstring(env->GetObjectField(obj, fieldId)));
+ if (strObj != nullptr) {
+ ScopedUtfChars chars(env, strObj.get());
+ return std::string(chars.c_str());
+ }
+ return std::string(defaultValue);
+}
+
+} // namespace android
+
+#endif // GRAPHICS_JNI_HELPERS
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/libs/hwui/jni/pdf/PdfDocument.cpp
index 5f67d3008f45..d21eb3f6a208 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/libs/hwui/jni/pdf/PdfDocument.cpp
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#include "jni.h"
#include "GraphicsJNI.h"
-#include "core_jni_helpers.h"
#include <vector>
#include "CreateJavaOutputStreamAdaptor.h"
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/libs/hwui/jni/pdf/PdfEditor.cpp
index 10c30260d7e3..828d6e3992b6 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/libs/hwui/jni/pdf/PdfEditor.cpp
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#undef LOG_TAG
#define LOG_TAG "PdfEditor"
#include <sys/types.h>
@@ -25,8 +27,7 @@
#include "PdfUtils.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include "graphics_jni_helpers.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
@@ -38,8 +39,6 @@
#include "SkMatrix.h"
-#include <core_jni_helpers.h>
-
namespace android {
enum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP};
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/libs/hwui/jni/pdf/PdfRenderer.cpp
index 761830b0e97c..cc1f96197c74 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/libs/hwui/jni/pdf/PdfRenderer.cpp
@@ -16,14 +16,11 @@
#include "PdfUtils.h"
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
#include "GraphicsJNI.h"
#include "SkBitmap.h"
#include "SkMatrix.h"
#include "fpdfview.h"
-#include "core_jni_helpers.h"
#include <vector>
#include <utils/Log.h>
#include <unistd.h>
diff --git a/core/jni/android/graphics/pdf/PdfUtils.cpp b/libs/hwui/jni/pdf/PdfUtils.cpp
index 36355ebbefc4..06d202828b85 100644
--- a/core/jni/android/graphics/pdf/PdfUtils.cpp
+++ b/libs/hwui/jni/pdf/PdfUtils.cpp
@@ -21,6 +21,7 @@
#include "fpdfview.h"
+#undef LOG_TAG
#define LOG_TAG "PdfUtils"
#include <utils/Log.h>
diff --git a/core/jni/android/graphics/pdf/PdfUtils.h b/libs/hwui/jni/pdf/PdfUtils.h
index 65327382e899..65327382e899 100644
--- a/core/jni/android/graphics/pdf/PdfUtils.h
+++ b/libs/hwui/jni/pdf/PdfUtils.h
diff --git a/libs/hwui/jni/scoped_nullable_primitive_array.h b/libs/hwui/jni/scoped_nullable_primitive_array.h
new file mode 100644
index 000000000000..77f4c9d14f07
--- /dev/null
+++ b/libs/hwui/jni/scoped_nullable_primitive_array.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+#define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+
+#include <jni.h>
+
+namespace android {
+
+#define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME) \
+class NAME ## ArrayTraits { \
+public: \
+ static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \
+ size_t len, POINTER_TYPE out) { \
+ env->Get ## NAME ## ArrayRegion(array, start, len, out); \
+ } \
+ \
+ static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) { \
+ return env->Get ## NAME ## ArrayElements(array, nullptr); \
+ } \
+ \
+ static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array, \
+ POINTER_TYPE buffer, jint mode) { \
+ env->Release ## NAME ## ArrayElements(array, buffer, mode); \
+ } \
+}; \
+
+ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean)
+ARRAY_TRAITS(jbyteArray, jbyte*, Byte)
+ARRAY_TRAITS(jcharArray, jchar*, Char)
+ARRAY_TRAITS(jdoubleArray, jdouble*, Double)
+ARRAY_TRAITS(jfloatArray, jfloat*, Float)
+ARRAY_TRAITS(jintArray, jint*, Int)
+ARRAY_TRAITS(jlongArray, jlong*, Long)
+ARRAY_TRAITS(jshortArray, jshort*, Short)
+
+#undef ARRAY_TRAITS
+
+template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10>
+class ScopedArrayRO {
+public:
+ ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
+ if (mJavaArray == nullptr) {
+ mSize = 0;
+ mRawArray = nullptr;
+ } else {
+ mSize = mEnv->GetArrayLength(mJavaArray);
+ if (mSize <= preallocSize) {
+ Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer);
+ mRawArray = mBuffer;
+ } else {
+ mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
+ }
+ }
+ }
+
+ ~ScopedArrayRO() {
+ if (mRawArray != nullptr && mRawArray != mBuffer) {
+ Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT);
+ }
+ }
+
+ const PrimitiveType* get() const { return mRawArray; }
+ const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; }
+ size_t size() const { return mSize; }
+
+private:
+ JNIEnv* const mEnv;
+ JavaArrayType mJavaArray;
+ PrimitiveType* mRawArray;
+ size_t mSize;
+ PrimitiveType mBuffer[preallocSize];
+ DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO);
+};
+
+// ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code.
+// These accept nullptr. In that case, get() returns nullptr and size() returns 0.
+using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>;
+using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>;
+using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>;
+using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>;
+using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>;
+using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>;
+using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>;
+using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>;
+
+} // namespace android
+
+#endif // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
diff --git a/core/jni/android/graphics/text/LineBreaker.cpp b/libs/hwui/jni/text/LineBreaker.cpp
index 8dae6558bb0d..69865171a09d 100644
--- a/core/jni/android/graphics/text/LineBreaker.cpp
+++ b/libs/hwui/jni/text/LineBreaker.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "LineBreaker"
#include "utils/misc.h"
#include "utils/Log.h"
+#include "graphics_jni_helpers.h"
#include <nativehelper/ScopedStringChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
#include "scoped_nullable_primitive_array.h"
#include <cstdint>
#include <vector>
diff --git a/core/jni/android/graphics/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index 3b5ecbcd1d35..7793746ee285 100644
--- a/core/jni/android/graphics/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#undef LOG_TAG
#define LOG_TAG "MeasuredText"
#include "GraphicsJNI.h"
@@ -21,8 +22,6 @@
#include "utils/Log.h"
#include <nativehelper/ScopedStringChars.h>
#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
#include <cstdint>
#include <vector>
#include <list>
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 6bb896fd7b29..88d6033ed9fb 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -23,6 +23,7 @@ cc_library_shared {
"libandroid_runtime",
"libbinder",
"libcutils",
+ "libhwui",
"liblog",
"libutils",
"libgui",
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index b1e3d6fe845a..213b3adfb2a8 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -20,6 +20,7 @@ cc_test {
shared_libs: [
"libandroid_runtime",
"libinputservice",
+ "libhwui",
"libgui",
"libutils",
],
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 19085bff0033..6028a8a90141 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -35,6 +35,7 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.PropertyInvalidatedCache;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
@@ -84,6 +85,23 @@ import java.util.function.Consumer;
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
+ @GuardedBy("mLock")
+ private PropertyInvalidatedCache<Integer, Boolean> mLocationEnabledCache =
+ new PropertyInvalidatedCache<Integer, Boolean>(
+ 4,
+ CACHE_KEY_LOCATION_ENABLED_PROPERTY) {
+ @Override
+ protected Boolean recompute(Integer userHandle) {
+ try {
+ return mService.isLocationEnabledForUser(userHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ };
+
+ private final Object mLock = new Object();
+
/**
* For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
* specific package.
@@ -462,6 +480,13 @@ public class LocationManager {
*/
@SystemApi
public boolean isLocationEnabledForUser(@NonNull UserHandle userHandle) {
+ synchronized (mLock) {
+ if (mLocationEnabledCache != null) {
+ return mLocationEnabledCache.query(userHandle.getIdentifier());
+ }
+ }
+
+ // fallback if cache is disabled
try {
return mService.isLocationEnabledForUser(userHandle.getIdentifier());
} catch (RemoteException e) {
@@ -3107,6 +3132,29 @@ public class LocationManager {
public void onLocationBatch(List<Location> locations) {
execute((listener) -> listener.onLocationBatch(locations));
}
+
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static final String CACHE_KEY_LOCATION_ENABLED_PROPERTY =
+ "cache_key.location_enabled";
+
+ /**
+ * @hide
+ */
+ public static void invalidateLocalLocationEnabledCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_LOCATION_ENABLED_PROPERTY);
+ }
+
+ /**
+ * @hide
+ */
+ public void disableLocalLocationEnabledCaches() {
+ synchronized (mLock) {
+ mLocationEnabledCache = null;
}
}
}
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 085602cbcd4f..6006d5079b07 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -27,22 +27,6 @@ import android.annotation.NonNull;
public abstract class LocationManagerInternal {
/**
- * Requests that a provider change its allowed state. A provider may or may not honor this
- * request, and if the provider does change its state as a result, that may happen
- * asynchronously after some delay.
- *
- * <p>Setting a provider's state to allowed implies that any consents or terms and conditions
- * that may be necessary to allow the provider are agreed to. Setting a providers state to
- * disallowed implies that any consents or terms and conditions have their agreement revoked.
- *
- * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
- * @param allowed Whether the location provider is being requested to allow or disallow
- * itself
- * @throws IllegalArgumentException if provider is null
- */
- public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed);
-
- /**
* Returns true if the given provider is enabled for the given user.
*
* @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index b7817ff1e1fc..4246c6cd1004 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -37,6 +37,4 @@ interface ILocationProvider {
@UnsupportedAppUsage
oneway void sendExtraCommand(String command, in Bundle extras);
-
- oneway void requestSetAllowed(boolean allowed);
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 49fcaabe981a..9cc30d0d751e 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -17,7 +17,6 @@ package com.android.location.provider {
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
method protected void onInit();
- method protected void onRequestSetAllowed(boolean);
method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public void reportLocation(android.location.Location);
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index bd29d8ac2a85..d3fb58fe257e 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -315,17 +315,6 @@ public abstract class LocationProviderBase {
return false;
}
- /**
- * Invoked when the system wishes to request that the provider sets its allowed state as
- * desired. This implies that the caller is providing/retracting consent for any terms and
- * conditions or consents associated with the provider.
- *
- * <p>It is generally only necessary to override this function if the provider has some barriers
- * or gates for enabling/disabling itself, in which case this function should handle those
- * appropriately. A provider that is always allowed has no need to override this function.
- */
- protected void onRequestSetAllowed(boolean allowed) {}
-
private final class Service extends ILocationProvider.Stub {
@Override
@@ -356,10 +345,5 @@ public abstract class LocationProviderBase {
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
-
- @Override
- public void requestSetAllowed(boolean allowed) {
- onRequestSetAllowed(allowed);
- }
}
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0b825f6dba54..383202b20550 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1654,6 +1654,12 @@ public class AudioManager {
* @hide
* Interface to be notified of changes in the preferred audio device set for a given audio
* strategy.
+ * <p>Note that this listener will only be invoked whenever
+ * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
+ * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
+ * preferred device. It will not be invoked directly after registration with
+ * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
+ * to indicate which strategies had preferred devices at the time of registration.</p>
* @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
* @see #removePreferredDeviceForStrategy(AudioProductStrategy)
* @see #getPreferredDeviceForStrategy(AudioProductStrategy)
diff --git a/media/java/android/media/IMediaRoute2ProviderService.aidl b/media/java/android/media/IMediaRoute2ProviderService.aidl
index cd0def30fa03..6cd2547dcbcf 100644
--- a/media/java/android/media/IMediaRoute2ProviderService.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderService.aidl
@@ -29,13 +29,13 @@ oneway interface IMediaRoute2ProviderService {
// MediaRoute2ProviderService#MediaRoute2ProviderServiceStub for readability.
void setCallback(IMediaRoute2ProviderServiceCallback callback);
void updateDiscoveryPreference(in RouteDiscoveryPreference discoveryPreference);
- void setRouteVolume(String routeId, int volume);
+ void setRouteVolume(String routeId, int volume, long requestId);
void requestCreateSession(String packageName, String routeId, long requestId,
in @nullable Bundle sessionHints);
- void selectRoute(String sessionId, String routeId);
- void deselectRoute(String sessionId, String routeId);
- void transferToRoute(String sessionId, String routeId);
- void setSessionVolume(String sessionId, int volume);
- void releaseSession(String sessionId);
+ void selectRoute(String sessionId, String routeId, long requestId);
+ void deselectRoute(String sessionId, String routeId, long requestId);
+ void transferToRoute(String sessionId, String routeId, long requestId);
+ void setSessionVolume(String sessionId, int volume, long requestId);
+ void releaseSession(String sessionId, long requestId);
}
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index e35b0c4a1fdd..ab42d75bf14f 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -31,4 +31,5 @@ oneway interface IMediaRoute2ProviderServiceCallback {
void notifySessionCreationFailed(long requestId);
void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
+ void notifyRequestFailed(long requestId, int reason);
}
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index ffad6592e902..a2f9ee906c03 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -30,4 +30,5 @@ oneway interface IMediaRouter2Manager {
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
+ void notifyRequestFailed(int requestId, int reason);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index cbec32386ed0..c7cb07d4ac1c 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -71,16 +71,17 @@ interface IMediaRouterService {
void registerManager(IMediaRouter2Manager manager, String packageName);
void unregisterManager(IMediaRouter2Manager manager);
void setRouteVolumeWithManager(IMediaRouter2Manager manager, in MediaRoute2Info route,
- int volume);
+ int volume, int requestId);
void requestCreateSessionWithManager(IMediaRouter2Manager manager, String packageName,
in @nullable MediaRoute2Info route, int requestId);
void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route);
+ in MediaRoute2Info route, int requestId);
void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route);
+ in MediaRoute2Info route, int requestId);
void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- in MediaRoute2Info route);
- void setSessionVolumeWithManager(IMediaRouter2Manager manager, String sessionId, int volume);
- void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId);
+ in MediaRoute2Info route, int requestId);
+ void setSessionVolumeWithManager(IMediaRouter2Manager manager, String sessionId, int volume,
+ int requestId);
+ void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId, int requestId);
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index abc7e0b7be0e..f2b4db1afdac 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1959,7 +1959,7 @@ final public class MediaCodec {
* If this codec is to be used with {@link LinearBlock} and/or {@link
* GraphicBlock}, pass this flag.
* <p>
- * When this flag is set, the following APIs throw IllegalStateException.
+ * When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
* <ul>
* <li>{@link #getInputBuffer}
* <li>{@link #getInputImage}
@@ -1986,6 +1986,12 @@ final public class MediaCodec {
public @interface ConfigureFlag {}
/**
+ * Thrown when the codec is configured for block model and an incompatible API is called.
+ */
+ public class IncompatibleWithBlockModelException extends RuntimeException {
+ }
+
+ /**
* Configures a component.
*
* @param format The format of the input data (decoder) or the desired
@@ -2526,7 +2532,7 @@ final public class MediaCodec {
throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2778,7 +2784,7 @@ final public class MediaCodec {
int flags) throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2813,7 +2819,7 @@ final public class MediaCodec {
public final int dequeueInputBuffer(long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
int res = native_dequeueInputBuffer(timeoutUs);
@@ -2848,7 +2854,7 @@ final public class MediaCodec {
public boolean isMappable() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
return mMappable;
}
@@ -2867,10 +2873,10 @@ final public class MediaCodec {
public @NonNull ByteBuffer map() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
if (!mMappable) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is not mappable");
}
if (mMapped == null) {
mMapped = native_map();
@@ -2896,7 +2902,7 @@ final public class MediaCodec {
public void recycle() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The linear block is invalid");
}
if (mMapped != null) {
mMapped.setAccessible(false);
@@ -3002,7 +3008,7 @@ final public class MediaCodec {
public boolean isMappable() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
return mMappable;
}
@@ -3021,10 +3027,10 @@ final public class MediaCodec {
public @NonNull Image map() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
if (!mMappable) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is not mappable");
}
if (mMapped == null) {
mMapped = native_map();
@@ -3050,7 +3056,7 @@ final public class MediaCodec {
public void recycle() {
synchronized (mLock) {
if (!mValid) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The graphic block is invalid");
}
if (mMapped != null) {
mMapped.close();
@@ -3127,8 +3133,9 @@ final public class MediaCodec {
if (buffer == null) {
buffer = new GraphicBlock();
}
- if (width < 0 || height < 0) {
- throw new IllegalArgumentException();
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException(
+ "non-positive width or height: " + width + "x" + height);
}
synchronized (buffer.mLock) {
buffer.native_obtain(width, height, format, usage, codecNames);
@@ -3177,16 +3184,8 @@ final public class MediaCodec {
* @param block The linear block object
* @param offset The byte offset into the input buffer at which the data starts.
* @param size The number of bytes of valid input data.
- * @param presentationTimeUs The presentation timestamp in microseconds for this
- * buffer. This is normally the media time at which this
- * buffer should be presented (rendered). When using an output
- * surface, this will be propagated as the {@link
- * SurfaceTexture#getTimestamp timestamp} for the frame (after
- * conversion to nanoseconds).
- * @param flags A bitmask of flags
- * {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
- * While not prohibited, most codecs do not use the
- * {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
+ * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
+ * may be null if clear.
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
@@ -3194,106 +3193,91 @@ final public class MediaCodec {
@NonNull LinearBlock block,
int offset,
int size,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ @Nullable MediaCodec.CryptoInfo cryptoInfo) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set block twice");
}
mLinearBlock = block;
mOffset = offset;
mSize = size;
- mPresentationTimeUs = presentationTimeUs;
- mFlags = flags;
+ mCryptoInfo = cryptoInfo;
return this;
}
/**
- * Set an encrypted linear block to this queue request. Exactly one
- * buffer must be set for a queue request before calling {@link #queue}.
+ * Set a graphic block to this queue request. Exactly one buffer must
+ * be set for a queue request before calling {@link #queue}.
*
- * @param block The linear block object
- * @param offset The byte offset into the input buffer at which the data starts.
- * @param presentationTimeUs The presentation timestamp in microseconds for this
- * buffer. This is normally the media time at which this
- * buffer should be presented (rendered). When using an output
- * surface, this will be propagated as the {@link
- * SurfaceTexture#getTimestamp timestamp} for the frame (after
- * conversion to nanoseconds).
- * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
- * @param flags A bitmask of flags
- * {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
- * While not prohibited, most codecs do not use the
- * {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
+ * @param block The graphic block object
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
- public @NonNull QueueRequest setEncryptedLinearBlock(
- @NonNull LinearBlock block,
- int offset,
- @NonNull MediaCodec.CryptoInfo cryptoInfo,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ public @NonNull QueueRequest setGraphicBlock(
+ @NonNull GraphicBlock block) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("Cannot set block twice");
}
- mLinearBlock = block;
- mOffset = offset;
- mCryptoInfo = cryptoInfo;
- mPresentationTimeUs = presentationTimeUs;
- mFlags = flags;
+ mGraphicBlock = block;
return this;
}
/**
- * Set a graphic block to this queue request. Exactly one buffer must
- * be set for a queue request before calling {@link #queue}.
+ * Set timestamp to this queue request.
*
- * @param block The graphic block object
* @param presentationTimeUs The presentation timestamp in microseconds for this
* buffer. This is normally the media time at which this
* buffer should be presented (rendered). When using an output
* surface, this will be propagated as the {@link
* SurfaceTexture#getTimestamp timestamp} for the frame (after
* conversion to nanoseconds).
+ * @return this object
+ */
+ public @NonNull QueueRequest setPresentationTimeUs(long presentationTimeUs) {
+ if (!isAccessible()) {
+ throw new IllegalStateException("The request is stale");
+ }
+ mPresentationTimeUs = presentationTimeUs;
+ return this;
+ }
+
+ /**
+ * Set flags to this queue request.
+ *
* @param flags A bitmask of flags
* {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
* While not prohibited, most codecs do not use the
* {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
* @return this object
- * @throws IllegalStateException if a buffer is already set
*/
- public @NonNull QueueRequest setGraphicBlock(
- @NonNull GraphicBlock block,
- long presentationTimeUs,
- @BufferFlag int flags) {
+ public @NonNull QueueRequest setFlags(@BufferFlag int flags) {
if (!isAccessible()) {
- throw new IllegalStateException();
- }
- if (mLinearBlock != null || mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
- mGraphicBlock = block;
- mPresentationTimeUs = presentationTimeUs;
mFlags = flags;
return this;
}
/**
- * Add a integer parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add an integer parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type int, that can also be set with {@link MediaFormat#setInteger}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setIntegerParameter(
@NonNull String key, int value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Integer.valueOf(value));
@@ -3301,15 +3285,20 @@ final public class MediaCodec {
}
/**
- * Add a long parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a long parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type long, that can also be set with {@link MediaFormat#setLong}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setLongParameter(
@NonNull String key, long value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Long.valueOf(value));
@@ -3317,15 +3306,20 @@ final public class MediaCodec {
}
/**
- * Add a float parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a float parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type float, that can also be set with {@link MediaFormat#setFloat}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setFloatParameter(
@NonNull String key, float value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(Float.valueOf(value));
@@ -3333,15 +3327,20 @@ final public class MediaCodec {
}
/**
- * Add a {@link ByteBuffer} parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a {@link ByteBuffer} parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of byte buffer, that can also be set with {@link MediaFormat#setByteBuffer}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setByteBufferParameter(
@NonNull String key, @NonNull ByteBuffer value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(value);
@@ -3349,15 +3348,20 @@ final public class MediaCodec {
}
/**
- * Add a string parameter. See {@link MediaFormat} for the list of
- * supported tunings. If there was {@link MediaCodec#setParameters}
+ * Add a string parameter.
+ * See {@link MediaFormat} for an exhaustive list of supported keys with
+ * values of type string, that can also be set with {@link MediaFormat#setString}.
+ *
+ * If there was {@link MediaCodec#setParameters}
* call with the same key which is not processed by the codec yet, the
* value set from this method will override the unprocessed value.
+ *
+ * @return this object
*/
public @NonNull QueueRequest setStringParameter(
@NonNull String key, @NonNull String value) {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
mTuningKeys.add(key);
mTuningValues.add(value);
@@ -3369,10 +3373,10 @@ final public class MediaCodec {
*/
public void queue() {
if (!isAccessible()) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The request is stale");
}
if (mLinearBlock == null && mGraphicBlock == null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("No block is set");
}
setAccessible(false);
if (mLinearBlock != null) {
@@ -3447,7 +3451,7 @@ final public class MediaCodec {
private final ArrayList<QueueRequest> mQueueRequests = new ArrayList<>();
/**
- * Return a clear {@link QueueRequest} object for an input slot index.
+ * Return a {@link QueueRequest} object for an input slot index.
*
* @param index input slot index from
* {@link Callback#onInputBufferAvailable}
@@ -3459,17 +3463,19 @@ final public class MediaCodec {
public @NonNull QueueRequest getQueueRequest(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_BLOCK) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The codec is not configured for block model");
}
if (index < 0 || index >= mQueueRequests.size()) {
- throw new IllegalArgumentException();
+ throw new IndexOutOfBoundsException("Expected range of index: [0,"
+ + (mQueueRequests.size() - 1) + "]; actual: " + index);
}
QueueRequest request = mQueueRequests.get(index);
if (request == null) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Unavailable index: " + index);
}
if (!request.isAccessible()) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(
+ "The request is stale at index " + index);
}
return request.clear();
}
@@ -3529,7 +3535,7 @@ final public class MediaCodec {
@NonNull BufferInfo info, long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
int res = native_dequeueOutputBuffer(info, timeoutUs);
@@ -3644,7 +3650,8 @@ final public class MediaCodec {
frame.clear();
break;
default:
- throw new IllegalStateException();
+ throw new IllegalStateException(
+ "Unrecognized buffer mode: " + mBufferMode);
}
}
releaseOutputBuffer(
@@ -3910,7 +3917,7 @@ final public class MediaCodec {
public ByteBuffer[] getInputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
if (mCachedInputBuffers == null) {
throw new IllegalStateException();
@@ -3946,7 +3953,7 @@ final public class MediaCodec {
public ByteBuffer[] getOutputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
if (mCachedOutputBuffers == null) {
throw new IllegalStateException();
@@ -3978,7 +3985,7 @@ final public class MediaCodec {
public ByteBuffer getInputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
ByteBuffer newBuffer = getBuffer(true /* input */, index);
@@ -4012,7 +4019,7 @@ final public class MediaCodec {
public Image getInputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
Image newImage = getImage(true /* input */, index);
@@ -4046,7 +4053,7 @@ final public class MediaCodec {
public ByteBuffer getOutputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
ByteBuffer newBuffer = getBuffer(false /* input */, index);
@@ -4079,7 +4086,7 @@ final public class MediaCodec {
public Image getOutputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_LEGACY) {
- throw new IllegalStateException();
+ throw new IncompatibleWithBlockModelException();
}
}
Image newImage = getImage(false /* input */, index);
@@ -4106,7 +4113,7 @@ final public class MediaCodec {
*/
public @Nullable LinearBlock getLinearBlock() {
if (mGraphicBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("This output frame is not linear");
}
return mLinearBlock;
}
@@ -4118,7 +4125,7 @@ final public class MediaCodec {
*/
public @Nullable GraphicBlock getGraphicBlock() {
if (mLinearBlock != null) {
- throw new IllegalStateException();
+ throw new IllegalStateException("This output frame is not graphic");
}
return mGraphicBlock;
}
@@ -4139,7 +4146,7 @@ final public class MediaCodec {
/**
* Returns a read-only {@link MediaFormat} for this frame. The returned
- * object is valid only while the client is holding the output frame.
+ * object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
*/
public @NonNull MediaFormat getFormat() {
return mFormat;
@@ -4151,7 +4158,7 @@ final public class MediaCodec {
* Client can find out what the change is by querying {@link MediaFormat}
* object returned from {@link #getFormat}.
*/
- public void getChangedKeys(@NonNull Set<String> keys) {
+ public void retrieveChangedKeys(@NonNull Set<String> keys) {
keys.clear();
keys.addAll(mChangedKeys);
}
@@ -4211,17 +4218,19 @@ final public class MediaCodec {
public @NonNull OutputFrame getOutputFrame(int index) {
synchronized (mBufferLock) {
if (mBufferMode != BUFFER_MODE_BLOCK) {
- throw new IllegalStateException();
+ throw new IllegalStateException("The codec is not configured for block model");
}
if (index < 0 || index >= mOutputFrames.size()) {
- throw new IllegalArgumentException();
+ throw new IndexOutOfBoundsException("Expected range of index: [0,"
+ + (mQueueRequests.size() - 1) + "]; actual: " + index);
}
OutputFrame frame = mOutputFrames.get(index);
if (frame == null) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Unavailable index: " + index);
}
if (!frame.isAccessible()) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(
+ "The output frame is stale at index " + index);
}
if (!frame.isLoaded()) {
native_getOutputFrame(frame, index);
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index bf04fe88f9e4..8d63cf04da6d 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -104,10 +104,12 @@ public final class MediaRoute2Info implements Parcelable {
/** @hide */
@IntDef({
- DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_REMOTE_TV,
- DEVICE_TYPE_REMOTE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
+ TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
+ TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE,
+ TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID,
+ TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP})
@Retention(RetentionPolicy.SOURCE)
- public @interface DeviceType {}
+ public @interface Type {}
/**
* The default receiver device type of the route indicating the type is unknown.
@@ -140,6 +142,121 @@ public final class MediaRoute2Info implements Parcelable {
*/
public static final int DEVICE_TYPE_BLUETOOTH = 3;
+
+ /**
+ * The default route type indicating the type is unknown.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_UNKNOWN = 0;
+
+ /**
+ * A route type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+ * in a device.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+
+ /**
+ * A route type describing a headset, which is the combination of a headphones and microphone.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
+
+ /**
+ * A route type describing a pair of wired headphones.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
+
+ /**
+ * A route type indicating the presentation of the media is happening
+ * on a bluetooth device such as a bluetooth speaker.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
+
+ /**
+ * A route type describing an HDMI connection.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
+
+ /**
+ * A route type describing a USB audio device.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
+
+ /**
+ * A route type describing a USB audio device in accessory mode.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
+
+ /**
+ * A route type describing the audio device associated with a dock.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
+
+ /**
+ * A device type describing a USB audio headset.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
+
+ /**
+ * A route type describing a Hearing Aid.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
+
+ /**
+ * A route type indicating the presentation of the media is happening on a TV.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_REMOTE_TV = 1001;
+
+ /**
+ * A route type indicating the presentation of the media is happening on a speaker.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_REMOTE_SPEAKER = 1002;
+
+ /**
+ * A route type indicating the presentation of the media is happening on multiple devices.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_GROUP = 2000;
+
/**
* Media feature: Live audio.
* <p>
@@ -196,8 +313,8 @@ public final class MediaRoute2Info implements Parcelable {
final String mId;
final CharSequence mName;
final List<String> mFeatures;
- @DeviceType
- final int mDeviceType;
+ @Type
+ final int mType;
final boolean mIsSystem;
final Uri mIconUri;
final CharSequence mDescription;
@@ -214,7 +331,7 @@ public final class MediaRoute2Info implements Parcelable {
mId = builder.mId;
mName = builder.mName;
mFeatures = builder.mFeatures;
- mDeviceType = builder.mDeviceType;
+ mType = builder.mType;
mIsSystem = builder.mIsSystem;
mIconUri = builder.mIconUri;
mDescription = builder.mDescription;
@@ -231,7 +348,7 @@ public final class MediaRoute2Info implements Parcelable {
mId = in.readString();
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mFeatures = in.createStringArrayList();
- mDeviceType = in.readInt();
+ mType = in.readInt();
mIsSystem = in.readBoolean();
mIconUri = in.readParcelable(null);
mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -285,9 +402,26 @@ public final class MediaRoute2Info implements Parcelable {
* {@link #DEVICE_TYPE_REMOTE_TV}, {@link #DEVICE_TYPE_REMOTE_SPEAKER},
* {@link #DEVICE_TYPE_BLUETOOTH}.
*/
- @DeviceType
+ @Type
public int getDeviceType() {
- return mDeviceType;
+ return getType();
+ }
+
+ /**
+ * Gets the type of this route.
+ *
+ * @return The type of this route:
+ * {@link #TYPE_UNKNOWN},
+ * {@link #TYPE_BUILTIN_SPEAKER}, {@link #TYPE_WIRED_HEADSET}, {@link #TYPE_WIRED_HEADPHONES},
+ * {@link #TYPE_BLUETOOTH_A2DP}, {@link #TYPE_HDMI}, {@link #TYPE_DOCK},
+ * {@Link #TYPE_USB_DEVICE}, {@link #TYPE_USB_ACCESSORY}, {@link #TYPE_USB_HEADSET}
+ * {@link #TYPE_HEARING_AID},
+ * {@link #TYPE_REMOTE_TV}, {@link #TYPE_REMOTE_SPEAKER}, {@link #TYPE_GROUP}.
+ * @hide
+ */
+ @Type
+ public int getType() {
+ return mType;
}
/**
@@ -437,7 +571,7 @@ public final class MediaRoute2Info implements Parcelable {
return Objects.equals(mId, other.mId)
&& Objects.equals(mName, other.mName)
&& Objects.equals(mFeatures, other.mFeatures)
- && (mDeviceType == other.mDeviceType)
+ && (mType == other.mType)
&& (mIsSystem == other.mIsSystem)
&& Objects.equals(mIconUri, other.mIconUri)
&& Objects.equals(mDescription, other.mDescription)
@@ -452,7 +586,7 @@ public final class MediaRoute2Info implements Parcelable {
@Override
public int hashCode() {
// Note: mExtras is not included.
- return Objects.hash(mId, mName, mFeatures, mDeviceType, mIsSystem, mIconUri, mDescription,
+ return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription,
mConnectionState, mClientPackageName, mVolumeHandling, mVolumeMax, mVolume,
mProviderId);
}
@@ -488,7 +622,7 @@ public final class MediaRoute2Info implements Parcelable {
dest.writeString(mId);
TextUtils.writeToParcel(mName, dest, flags);
dest.writeStringList(mFeatures);
- dest.writeInt(mDeviceType);
+ dest.writeInt(mType);
dest.writeBoolean(mIsSystem);
dest.writeParcelable(mIconUri, flags);
TextUtils.writeToParcel(mDescription, dest, flags);
@@ -509,8 +643,8 @@ public final class MediaRoute2Info implements Parcelable {
final CharSequence mName;
final List<String> mFeatures;
- @DeviceType
- int mDeviceType = DEVICE_TYPE_UNKNOWN;
+ @Type
+ int mType = TYPE_UNKNOWN;
boolean mIsSystem;
Uri mIconUri;
CharSequence mDescription;
@@ -557,7 +691,7 @@ public final class MediaRoute2Info implements Parcelable {
mId = routeInfo.mId;
mName = routeInfo.mName;
mFeatures = new ArrayList<>(routeInfo.mFeatures);
- mDeviceType = routeInfo.mDeviceType;
+ mType = routeInfo.mType;
mIsSystem = routeInfo.mIsSystem;
mIconUri = routeInfo.mIconUri;
mDescription = routeInfo.mDescription;
@@ -621,8 +755,17 @@ public final class MediaRoute2Info implements Parcelable {
* Sets the route's device type.
*/
@NonNull
- public Builder setDeviceType(@DeviceType int deviceType) {
- mDeviceType = deviceType;
+ public Builder setDeviceType(@Type int type) {
+ return setType(type);
+ }
+
+ /**
+ * Sets the route's type.
+ * @hide
+ */
+ @NonNull
+ public Builder setType(@Type int type) {
+ mType = type;
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 38233fd06745..aa0eda1fdbb1 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -19,6 +19,7 @@ package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -37,6 +38,8 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -51,7 +54,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Media apps which use {@link MediaRouter2} can request to play their media on the routes.
* </p><p>
* When {@link MediaRouter2 media router} wants to play media on a route,
- * {@link #onCreateSession(String, String, long, Bundle)} will be called to handle the request.
+ * {@link #onCreateSession(long, String, String, Bundle)} will be called to handle the request.
* A session can be considered as a group of currently selected routes for each connection.
* Create and manage the sessions by yourself, and notify the {@link RoutingSessionInfo
* session infos} when there are any changes.
@@ -61,6 +64,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
* a {@link MediaRouter2 media router} by an application. See
* {@link #onDiscoveryPreferenceChanged(RouteDiscoveryPreference)} for the details.
* </p>
+ * Use {@link #notifyRequestFailed(long, int)} to notify the failure with previously received
+ * request ID.
*/
public abstract class MediaRoute2ProviderService extends Service {
private static final String TAG = "MR2ProviderService";
@@ -79,7 +84,53 @@ public abstract class MediaRoute2ProviderService extends Service {
*
* @see #notifySessionCreated(RoutingSessionInfo, long)
*/
- public static final long REQUEST_ID_UNKNOWN = 0;
+ public static final long REQUEST_ID_NONE = 0;
+
+ /**
+ * The request has failed due to unknown reason.
+ *
+ * @see #notifyRequestFailed(long, int)
+ */
+ public static final int REASON_UNKNOWN_ERROR = 0;
+
+ /**
+ * The request has failed since this service rejected the request.
+ *
+ * @see #notifyRequestFailed(long, int)
+ */
+ public static final int REASON_REJECTED = 1;
+
+ /**
+ * The request has failed due to a network error.
+ *
+ * @see #notifyRequestFailed(long, int)
+ */
+ public static final int REASON_NETWORK_ERROR = 2;
+
+ /**
+ * The request has failed since the requested route is no longer available.
+ *
+ * @see #notifyRequestFailed(long, int)
+ */
+ public static final int REASON_ROUTE_NOT_AVAILABLE = 3;
+
+ /**
+ * The request has failed since the request is not valid. For example, selecting a route
+ * which is not selectable.
+ *
+ * @see #notifyRequestFailed(long, int)
+ */
+ public static final int REASON_INVALID_COMMAND = 4;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = "REASON_", value = {
+ REASON_UNKNOWN_ERROR, REASON_REJECTED, REASON_NETWORK_ERROR, REASON_ROUTE_NOT_AVAILABLE,
+ REASON_INVALID_COMMAND
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Reason {}
private final Handler mHandler;
private final Object mSessionLock = new Object();
@@ -116,20 +167,23 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when a volume setting is requested on a route of the provider
*
+ * @param requestId the id of this request
* @param routeId the id of the route
* @param volume the target volume
- * @see MediaRoute2Info#getVolumeMax()
+ * @see MediaRoute2Info.Builder#setVolume(int)
*/
- public abstract void onSetRouteVolume(@NonNull String routeId, int volume);
+ public abstract void onSetRouteVolume(long requestId, @NonNull String routeId, int volume);
/**
* Called when {@link MediaRouter2.RoutingController#setVolume(int)} is called on
* a routing session of the provider
*
+ * @param requestId the id of this request
* @param sessionId the id of the routing session
* @param volume the target volume
+ * @see RoutingSessionInfo.Builder#setVolume(int)
*/
- public abstract void onSetSessionVolume(@NonNull String sessionId, int volume);
+ public abstract void onSetSessionVolume(long requestId, @NonNull String sessionId, int volume);
/**
* Gets information of the session with the given id.
@@ -161,14 +215,15 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Notifies clients of that the session is created and ready for use.
* <p>
- * If this session is created without any creation request, use {@link #REQUEST_ID_UNKNOWN}
+ * If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
* as the request ID.
*
* @param sessionInfo information of the new session.
* The {@link RoutingSessionInfo#getId() id} of the session must be unique.
* @param requestId id of the previous request to create this session provided in
- * {@link #onCreateSession(String, String, long, Bundle)}
- * @see #onCreateSession(String, String, long, Bundle)
+ * {@link #onCreateSession(long, String, String, Bundle)}. Can be
+ * {@link #REQUEST_ID_NONE} if this session is created without any request.
+ * @see #onCreateSession(long, String, String, Bundle)
* @see #getSessionInfo(String)
*/
public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo,
@@ -201,8 +256,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* Notifies clients of that the session could not be created.
*
* @param requestId id of the previous request to create the session provided in
- * {@link #onCreateSession(String, String, long, Bundle)}.
- * @see #onCreateSession(String, String, long, Bundle)
+ * {@link #onCreateSession(long, String, String, Bundle)}.
+ * @see #onCreateSession(long, String, String, Bundle)
*/
public final void notifySessionCreationFailed(long requestId) {
if (mRemoteCallback == null) {
@@ -246,7 +301,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* Notifies that the session is released.
*
* @param sessionId id of the released session.
- * @see #onReleaseSession(String)
+ * @see #onReleaseSession(long, String)
*/
public final void notifySessionReleased(@NonNull String sessionId) {
if (TextUtils.isEmpty(sessionId)) {
@@ -273,6 +328,29 @@ public abstract class MediaRoute2ProviderService extends Service {
}
/**
+ * Notifies to the client that the request has failed.
+ *
+ * @param requestId the ID of the previous request
+ * @param reason the reason why the request has failed
+ *
+ * @see #REASON_UNKNOWN_ERROR
+ * @see #REASON_REJECTED
+ * @see #REASON_NETWORK_ERROR
+ * @see #REASON_ROUTE_NOT_AVAILABLE
+ * @see #REASON_INVALID_COMMAND
+ */
+ public final void notifyRequestFailed(long requestId, @Reason int reason) {
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifyRequestFailed(requestId, reason);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify that the request has failed.");
+ }
+ }
+
+ /**
* Called when the service receives a request to create a session.
* <p>
* You should create and maintain your own session and notifies the client of
@@ -288,9 +366,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* If you can't create the session or want to reject the request, call
* {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
*
+ * @param requestId the id of this request
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route initially being connected
- * @param requestId the id of this session creation request
* @param sessionHints an optional bundle of app-specific arguments sent by
* {@link MediaRouter2}, or null if none. The contents of this bundle
* may affect the result of session creation.
@@ -299,8 +377,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* @see RoutingSessionInfo.Builder#addSelectedRoute(String)
* @see RoutingSessionInfo.Builder#setControlHints(Bundle)
*/
- public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
- long requestId, @Nullable Bundle sessionHints);
+ public abstract void onCreateSession(long requestId, @NonNull String packageName,
+ @NonNull String routeId, @Nullable Bundle sessionHints);
/**
* Called when the session should be released. A client of the session or system can request
@@ -312,44 +390,48 @@ public abstract class MediaRoute2ProviderService extends Service {
* Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
* this method to be called.
*
+ * @param requestId the id of this request
* @param sessionId id of the session being released.
* @see #notifySessionReleased(String)
* @see #getSessionInfo(String)
*/
- public abstract void onReleaseSession(@NonNull String sessionId);
+ public abstract void onReleaseSession(long requestId, @NonNull String sessionId);
- //TODO: make a way to reject the request
/**
* Called when a client requests selecting a route for the session.
* After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
+ * @param requestId the id of this request
* @param sessionId id of the session
* @param routeId id of the route
*/
- public abstract void onSelectRoute(@NonNull String sessionId, @NonNull String routeId);
+ public abstract void onSelectRoute(long requestId, @NonNull String sessionId,
+ @NonNull String routeId);
- //TODO: make a way to reject the request
/**
* Called when a client requests deselecting a route from the session.
* After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
+ * @param requestId the id of this request
* @param sessionId id of the session
* @param routeId id of the route
*/
- public abstract void onDeselectRoute(@NonNull String sessionId, @NonNull String routeId);
+ public abstract void onDeselectRoute(long requestId, @NonNull String sessionId,
+ @NonNull String routeId);
- //TODO: make a way to reject the request
/**
* Called when a client requests transferring a session to a route.
* After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
+ * @param requestId the id of this request
* @param sessionId id of the session
* @param routeId id of the route
*/
- public abstract void onTransferToRoute(@NonNull String sessionId, @NonNull String routeId);
+ public abstract void onTransferToRoute(long requestId, @NonNull String sessionId,
+ @NonNull String routeId);
/**
* Called when the {@link RouteDiscoveryPreference discovery preference} has changed.
@@ -439,12 +521,12 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public void setRouteVolume(String routeId, int volume) {
+ public void setRouteVolume(String routeId, int volume, long requestId) {
if (!checkCallerisSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
- MediaRoute2ProviderService.this, routeId, volume));
+ MediaRoute2ProviderService.this, requestId, routeId, volume));
}
@Override
@@ -454,12 +536,12 @@ public abstract class MediaRoute2ProviderService extends Service {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
- MediaRoute2ProviderService.this, packageName, routeId, requestId,
+ MediaRoute2ProviderService.this, requestId, packageName, routeId,
requestCreateSession));
}
@Override
- public void selectRoute(@NonNull String sessionId, String routeId) {
+ public void selectRoute(String sessionId, String routeId, long requestId) {
if (!checkCallerisSystem()) {
return;
}
@@ -468,11 +550,11 @@ public abstract class MediaRoute2ProviderService extends Service {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
- MediaRoute2ProviderService.this, sessionId, routeId));
+ MediaRoute2ProviderService.this, requestId, sessionId, routeId));
}
@Override
- public void deselectRoute(@NonNull String sessionId, String routeId) {
+ public void deselectRoute(String sessionId, String routeId, long requestId) {
if (!checkCallerisSystem()) {
return;
}
@@ -481,11 +563,11 @@ public abstract class MediaRoute2ProviderService extends Service {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
- MediaRoute2ProviderService.this, sessionId, routeId));
+ MediaRoute2ProviderService.this, requestId, sessionId, routeId));
}
@Override
- public void transferToRoute(@NonNull String sessionId, String routeId) {
+ public void transferToRoute(String sessionId, String routeId, long requestId) {
if (!checkCallerisSystem()) {
return;
}
@@ -494,20 +576,20 @@ public abstract class MediaRoute2ProviderService extends Service {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
- MediaRoute2ProviderService.this, sessionId, routeId));
+ MediaRoute2ProviderService.this, requestId, sessionId, routeId));
}
@Override
- public void setSessionVolume(String sessionId, int volume) {
+ public void setSessionVolume(String sessionId, int volume, long requestId) {
if (!checkCallerisSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
- MediaRoute2ProviderService.this, sessionId, volume));
+ MediaRoute2ProviderService.this, requestId, sessionId, volume));
}
@Override
- public void releaseSession(@NonNull String sessionId) {
+ public void releaseSession(String sessionId, long requestId) {
if (!checkCallerisSystem()) {
return;
}
@@ -516,7 +598,7 @@ public abstract class MediaRoute2ProviderService extends Service {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
- MediaRoute2ProviderService.this, sessionId));
+ MediaRoute2ProviderService.this, requestId, sessionId));
}
}
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 5942a3d05e67..34109194acba 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -817,7 +817,7 @@ public class MediaRouter2 {
* @return An optional bundle of app-specific arguments to send to the provider,
* or null if none. The contents of this bundle may affect the result of
* controller creation.
- * @see MediaRoute2ProviderService#onCreateSession(String, String, long, Bundle)
+ * @see MediaRoute2ProviderService#onCreateSession(long, String, String, Bundle)
*/
@Nullable
Bundle onGetControllerHints(@NonNull MediaRoute2Info route);
@@ -976,8 +976,12 @@ public class MediaRouter2 {
}
/**
- * Selects a route for the remote session. The given route must satisfy all of the
- * following conditions:
+ * Selects a route for the remote session. After a route is selected, the media is expected
+ * to be played to the all the selected routes. This is different from {@link
+ * MediaRouter2#transferTo(MediaRoute2Info)} transferring to a route},
+ * where the media is expected to 'move' from one route to another.
+ * <p>
+ * The given route must satisfy all of the following conditions:
* <ul>
* <li>ID should not be included in {@link #getSelectedRoutes()}</li>
* <li>ID should be included in {@link #getSelectableRoutes()}</li>
@@ -1024,8 +1028,10 @@ public class MediaRouter2 {
}
/**
- * Deselects a route from the remote session. The given route must satisfy all of the
- * following conditions:
+ * Deselects a route from the remote session. After a route is deselected, the media is
+ * expected to be stopped on the deselected routes.
+ * <p>
+ * The given route must satisfy all of the following conditions:
* <ul>
* <li>ID should be included in {@link #getSelectedRoutes()}</li>
* <li>ID should be included in {@link #getDeselectableRoutes()}</li>
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 636ee92f68a8..ff2c863aa7b0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -337,7 +337,8 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
- mMediaRouterService.setRouteVolumeWithManager(client, route, volume);
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.setRouteVolumeWithManager(client, route, volume, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to send control request.", ex);
}
@@ -368,8 +369,9 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
+ int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.setSessionVolumeWithManager(
- client, sessionInfo.getId(), volume);
+ client, sessionInfo.getId(), volume, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to send control request.", ex);
}
@@ -443,6 +445,12 @@ public class MediaRouter2Manager {
}
}
+ void notifyRequestFailed(int reason) {
+ for (CallbackRecord record : mCallbackRecords) {
+ record.mExecutor.execute(() -> record.mCallback.onRequestFailed(reason));
+ }
+ }
+
void updatePreferredFeatures(String packageName, List<String> preferredFeatures) {
List<String> prevFeatures = mPreferredFeaturesMap.put(packageName, preferredFeatures);
if ((prevFeatures == null && preferredFeatures.size() == 0)
@@ -593,7 +601,9 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
- mMediaRouterService.selectRouteWithManager(mClient, getSessionId(), route);
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.selectRouteWithManager(
+ mClient, getSessionId(), route, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select route for session.", ex);
}
@@ -635,7 +645,9 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
- mMediaRouterService.deselectRouteWithManager(mClient, getSessionId(), route);
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.deselectRouteWithManager(
+ mClient, getSessionId(), route, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to remove route from session.", ex);
}
@@ -678,7 +690,9 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
- mMediaRouterService.transferToRouteWithManager(mClient, getSessionId(), route);
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.transferToRouteWithManager(
+ mClient, getSessionId(), route, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to transfer to route for session.", ex);
}
@@ -696,7 +710,9 @@ public class MediaRouter2Manager {
}
if (client != null) {
try {
- mMediaRouterService.releaseSessionWithManager(mClient, getSessionId());
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.releaseSessionWithManager(
+ mClient, getSessionId(), requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to notify of controller release", ex);
}
@@ -783,6 +799,17 @@ public class MediaRouter2Manager {
public void onPreferredFeaturesChanged(@NonNull String packageName,
@NonNull List<String> preferredFeatures) {}
+ /**
+ * Called when a previous request has failed.
+ *
+ * @param reason the reason that the request has failed. Can be one of followings:
+ * {@link MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+ * {@link MediaRoute2ProviderService#REASON_REJECTED},
+ * {@link MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+ * {@link MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+ * {@link MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+ */
+ public void onRequestFailed(int reason) {}
}
final class CallbackRecord {
@@ -826,6 +853,13 @@ public class MediaRouter2Manager {
}
@Override
+ public void notifyRequestFailed(int requestId, int reason) {
+ // Note: requestId is not used.
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRequestFailed,
+ MediaRouter2Manager.this, reason));
+ }
+
+ @Override
public void notifyPreferredFeaturesChanged(String packageName, List<String> features) {
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updatePreferredFeatures,
MediaRouter2Manager.this, packageName, features));
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index e80562b3fd1c..bcff6a1df918 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -19,6 +19,8 @@ package com.android.mediaroutertest;
import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
+import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SPECIAL;
@@ -32,6 +34,7 @@ import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE
import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.VOLUME_MAX;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -55,7 +58,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -69,6 +71,7 @@ import java.util.function.Predicate;
@SmallTest
public class MediaRouter2ManagerTest {
private static final String TAG = "MediaRouter2ManagerTest";
+ private static final int WAIT_TIME_MS = 2000;
private static final int TIMEOUT_MS = 5000;
private Context mContext;
@@ -111,6 +114,11 @@ public class MediaRouter2ManagerTest {
releaseAllSessions();
// unregister callbacks
clearCallbacks();
+
+ SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+ if (instance != null) {
+ instance.setProxy(null);
+ }
}
@Test
@@ -296,7 +304,7 @@ public class MediaRouter2ManagerTest {
String selectedSystemRouteId =
MediaRouter2Utils.getOriginalId(
mManager.getActiveSessions().get(0).getSelectedRoutes().get(0));
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(Collections.emptyList());
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
MediaRoute2Info volRoute = routes.get(selectedSystemRouteId);
assertNotNull(volRoute);
@@ -398,6 +406,53 @@ public class MediaRouter2ManagerTest {
}
}
+ /**
+ * Tests that {@link android.media.MediaRoute2ProviderService#notifyRequestFailed(long, int)}
+ * should invoke the callback only when the right requestId is used.
+ */
+ @Test
+ public void testOnRequestFailedCalledForProperRequestId() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+
+ SampleMediaRoute2ProviderService instance = SampleMediaRoute2ProviderService.getInstance();
+ assertNotNull(instance);
+
+ final List<Long> requestIds = new ArrayList<>();
+ final CountDownLatch onSetRouteVolumeLatch = new CountDownLatch(1);
+ instance.setProxy(new SampleMediaRoute2ProviderService.Proxy() {
+ @Override
+ public void onSetRouteVolume(String routeId, int volume, long requestId) {
+ requestIds.add(requestId);
+ onSetRouteVolumeLatch.countDown();
+ }
+ });
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {});
+ mManager.setRouteVolume(volRoute, 0);
+ assertTrue(onSetRouteVolumeLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertFalse(requestIds.isEmpty());
+
+ final int failureReason = REASON_REJECTED;
+ final CountDownLatch onRequestFailedLatch = new CountDownLatch(1);
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onRequestFailed(int reason) {
+ if (reason == failureReason) {
+ onRequestFailedLatch.countDown();
+ }
+ }
+ });
+
+ final long invalidRequestId = REQUEST_ID_NONE;
+ instance.notifyRequestFailed(invalidRequestId, failureReason);
+ assertFalse(onRequestFailedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ final long validRequestId = requestIds.get(0);
+ instance.notifyRequestFailed(validRequestId, failureReason);
+ assertTrue(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
@Test
public void testVolumeHandling() throws Exception {
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
@@ -429,10 +484,11 @@ public class MediaRouter2ManagerTest {
}
@Override
- public void onControlCategoriesChanged(String packageName,
+ public void onPreferredFeaturesChanged(String packageName,
List<String> preferredFeatures) {
if (TextUtils.equals(mPackageName, packageName)
- && preferredFeatures.equals(routeFeatures)) {
+ && preferredFeatures.size() == routeFeatures.size()
+ && preferredFeatures.containsAll(routeFeatures)) {
featuresLatch.countDown();
}
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 3faefdb148e1..0e7c7fc499b4 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -16,9 +16,9 @@
package com.android.mediaroutertest;
-import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER;
-import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -75,15 +75,16 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
@GuardedBy("sLock")
private static SampleMediaRoute2ProviderService sInstance;
+ private Proxy mProxy;
private void initializeRoutes() {
MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
.addFeature(FEATURE_SAMPLE)
- .setDeviceType(DEVICE_TYPE_REMOTE_TV)
+ .setType(TYPE_REMOTE_TV)
.build();
MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
.addFeature(FEATURE_SAMPLE)
- .setDeviceType(DEVICE_TYPE_REMOTE_SPEAKER)
+ .setType(TYPE_REMOTE_SPEAKER)
.build();
MediaRoute2Info route3 = new MediaRoute2Info.Builder(
ROUTE_ID3_SESSION_CREATION_FAILED, ROUTE_NAME3)
@@ -179,7 +180,13 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSetRouteVolume(String routeId, int volume) {
+ public void onSetRouteVolume(long requestId, String routeId, int volume) {
+ Proxy proxy = mProxy;
+ if (proxy != null) {
+ proxy.onSetRouteVolume(routeId, volume, requestId);
+ return;
+ }
+
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null) {
return;
@@ -192,7 +199,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSetSessionVolume(String sessionId, int volume) {
+ public void onSetSessionVolume(long requestId, String sessionId, int volume) {
RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
if (sessionInfo == null) {
return;
@@ -205,7 +212,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onCreateSession(String packageName, String routeId, long requestId,
+ public void onCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle sessionHints) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
@@ -238,7 +245,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onReleaseSession(String sessionId) {
+ public void onReleaseSession(long requestId, String sessionId) {
RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
if (sessionInfo == null) {
return;
@@ -258,7 +265,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSelectRoute(String sessionId, String routeId) {
+ public void onSelectRoute(long requestId, String sessionId, String routeId) {
RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || sessionInfo == null) {
@@ -280,7 +287,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onDeselectRoute(String sessionId, String routeId) {
+ public void onDeselectRoute(long requestId, String sessionId, String routeId) {
RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
MediaRoute2Info route = mRoutes.get(routeId);
@@ -308,7 +315,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onTransferToRoute(String sessionId, String routeId) {
+ public void onTransferToRoute(long requestId, String sessionId, String routeId) {
RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
MediaRoute2Info route = mRoutes.get(routeId);
@@ -347,10 +354,18 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
String sessionId = mRouteIdToSessionId.get(routeId);
- onDeselectRoute(sessionId, routeId);
+ onDeselectRoute(REQUEST_ID_NONE, sessionId, routeId);
}
void publishRoutes() {
notifyRoutes(mRoutes.values());
}
+
+ public void setProxy(@Nullable Proxy proxy) {
+ mProxy = proxy;
+ }
+
+ public static class Proxy {
+ public void onSetRouteVolume(String routeId, int volume, long requestId) {}
+ }
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 257ae7332cc1..ed73f39e57f8 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -51,6 +51,7 @@ cc_library_shared {
"surface_control.cpp",
"system_fonts.cpp",
"trace.cpp",
+ "thermal.cpp"
],
shared_libs: [
@@ -72,6 +73,7 @@ cc_library_shared {
"libxml2",
"libEGL",
"libGLESv2",
+ "libpowermanager",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
],
@@ -81,6 +83,8 @@ cc_library_shared {
"libarect",
],
+ header_libs: [ "libhwui_internal_headers" ],
+
whole_static_libs: ["libnativedisplay", "libnativewindow"],
export_static_lib_headers: ["libarect"],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index a8f1d2c7bbba..d56aa86ae6fa 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -280,6 +280,11 @@ LIBANDROID {
android_res_nquery; # introduced=29
android_res_nresult; # introduced=29
android_res_nsend; # introduced=29
+ AThermal_acquireManager; # introduced=30
+ AThermal_releaseManager; # introduced=30
+ AThermal_getCurrentThermalStatus; # introduced=30
+ AThermal_registerThermalStatusListener; # introduced=30
+ AThermal_unregisterThermalStatusListener; # introduced=30
local:
*;
};
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
new file mode 100644
index 000000000000..545c423908a0
--- /dev/null
+++ b/native/android/thermal.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "thermal"
+
+#include <cerrno>
+#include <thread>
+
+#include <android/thermal.h>
+#include <android/os/BnThermalStatusListener.h>
+#include <android/os/IThermalService.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+using android::sp;
+
+using namespace android;
+using namespace android::os;
+
+struct ThermalServiceListener : public BnThermalStatusListener {
+ public:
+ virtual binder::Status onStatusChange(int32_t status) override;
+ ThermalServiceListener(AThermalManager *manager) {mMgr = manager;}
+ private:
+ AThermalManager *mMgr;
+};
+
+struct ListenerCallback {
+ AThermal_StatusCallback callback;
+ void* data;
+};
+
+struct AThermalManager {
+ public:
+ static AThermalManager* createAThermalManager();
+ AThermalManager() = delete;
+ ~AThermalManager();
+ status_t notifyStateChange(int32_t status);
+ status_t getCurrentThermalStatus(int32_t *status);
+ status_t addListener(AThermal_StatusCallback, void *data);
+ status_t removeListener(AThermal_StatusCallback, void *data);
+ private:
+ AThermalManager(sp<IThermalService> service);
+ sp<IThermalService> mThermalSvc;
+ sp<ThermalServiceListener> mServiceListener;
+ std::vector<ListenerCallback> mListeners;
+ std::mutex mMutex;
+};
+
+binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
+ if (mMgr != nullptr) {
+ mMgr->notifyStateChange(status);
+ }
+ return binder::Status::ok();
+}
+
+AThermalManager* AThermalManager::createAThermalManager() {
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("thermalservice"));
+
+ if (binder == nullptr) {
+ ALOGE("%s: Thermal service is not ready ", __FUNCTION__);
+ return nullptr;
+ }
+ return new AThermalManager(interface_cast<IThermalService>(binder));
+}
+
+AThermalManager::AThermalManager(sp<IThermalService> service)
+ : mThermalSvc(service),
+ mServiceListener(nullptr) {
+}
+
+AThermalManager::~AThermalManager() {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ mListeners.clear();
+ if (mServiceListener != nullptr) {
+ bool success = false;
+ mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ mServiceListener = nullptr;
+ }
+}
+
+status_t AThermalManager::notifyStateChange(int32_t status) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
+
+ for (auto listener : mListeners) {
+ listener.callback(listener.data, thermalStatus);
+ }
+ return OK;
+}
+
+status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (callback == nullptr) {
+ // Callback can not be nullptr
+ return EINVAL;
+ }
+ for (const auto& cb : mListeners) {
+ // Don't re-add callbacks.
+ if (callback == cb.callback && data == cb.data) {
+ return EINVAL;
+ }
+ }
+ mListeners.emplace_back(ListenerCallback{callback, data});
+
+ if (mServiceListener != nullptr) {
+ return OK;
+ }
+ bool success = false;
+ mServiceListener = new ThermalServiceListener(this);
+ if (mServiceListener == nullptr) {
+ return ENOMEM;
+ }
+ auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in registerThermalStatusListener %d", success);
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ return OK;
+}
+
+status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ auto it = std::remove_if(mListeners.begin(),
+ mListeners.end(),
+ [&](const ListenerCallback& cb) {
+ return callback == cb.callback &&
+ data == cb.data;
+ });
+ if (it == mListeners.end()) {
+ // If the listener and data pointer were not previously added.
+ return EINVAL;
+ }
+ mListeners.erase(it, mListeners.end());
+
+ if (!mListeners.empty()) {
+ return OK;
+ }
+ if (mServiceListener == nullptr) {
+ return OK;
+ }
+ bool success = false;
+ auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+ if (!success || !ret.isOk()) {
+ ALOGE("Failed in unregisterThermalStatusListener %d", success);
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ mServiceListener = nullptr;
+ return OK;
+}
+
+status_t AThermalManager::getCurrentThermalStatus(int32_t *status) {
+ binder::Status ret = mThermalSvc->getCurrentThermalStatus(status);
+
+ if (!ret.isOk()) {
+ if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ return OK;
+}
+
+/**
+ * Acquire an instance of the thermal manager. This must be freed using
+ * {@link AThermal_releaseManager}.
+ *
+ * @return manager instance on success, nullptr on failure.
+ */
+AThermalManager* AThermal_acquireManager() {
+ auto manager = AThermalManager::createAThermalManager();
+
+ return manager;
+}
+
+/**
+ * Release the thermal manager pointer acquired by
+ * {@link AThermal_acquireManager}.
+ *
+ * @param manager The manager to be released.
+ *
+ */
+void AThermal_releaseManager(AThermalManager *manager) {
+ delete manager;
+}
+
+/**
+ * Gets the current thermal status.
+ *
+ * @param manager The manager instance to use to query the thermal status,
+ * acquired by {@link AThermal_acquireManager}.
+ *
+ * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
+*/
+AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
+ int32_t status = 0;
+ status_t ret = manager->getCurrentThermalStatus(&status);
+ if (ret != OK) {
+ return AThermalStatus::ATHERMAL_STATUS_ERROR;
+ }
+ return static_cast<AThermalStatus>(status);
+}
+
+/**
+ * Register the thermal status listener for thermal status change.
+ *
+ * @param manager The manager instance to use to register.
+ * acquired by {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were previously added and not removed.
+ * EPERM if the required permission is not held.
+ * EPIPE if communication with the system service has failed.
+ */
+int AThermal_registerThermalStatusListener(AThermalManager *manager,
+ AThermal_StatusCallback callback, void *data) {
+ return manager->addListener(callback, data);
+}
+
+/**
+ * Unregister the thermal status listener previously resgistered.
+ *
+ * @param manager The manager instance to use to unregister.
+ * acquired by {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ * EINVAL if the listener and data pointer were not previously added.
+ * EPERM if the required permission is not held.
+ * EPIPE if communication with the system service has failed.
+ */
+int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
+ AThermal_StatusCallback callback, void *data) {
+ return manager->removeListener(callback, data);
+}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 376ea77740c2..15b473c2a6ab 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -37,6 +37,8 @@ cc_library_shared {
"liblog",
],
+ header_libs: [ "libhwui_internal_headers" ],
+
static_libs: ["libarect"],
arch: {
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index d1946b085df4..56f390698eb2 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -20,7 +20,7 @@
#include <android/bitmap.h>
#include <android/data_space.h>
#include <android/imagedecoder.h>
-#include <android/graphics/MimeType.h>
+#include <MimeType.h>
#include <android/rect.h>
#include <hwui/ImageDecoder.h>
#include <log/log.h>
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 88decc86c387..1a3b36d046e1 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -30,12 +30,14 @@ cc_library_shared {
"graphic_buffer_impl.cpp",
],
+ header_libs: [ "libhwui_internal_headers" ],
+
shared_libs: [
"libandroidfw",
- "libandroid_runtime",
"libcutils",
"libhwui",
"liblog",
+ "libnativehelper",
"libui",
"libutils",
"libvulkan",
diff --git a/native/webview/plat_support/graphics_utils.cpp b/native/webview/plat_support/graphics_utils.cpp
index 56825cee4520..8d7a59e46e72 100644
--- a/native/webview/plat_support/graphics_utils.cpp
+++ b/native/webview/plat_support/graphics_utils.cpp
@@ -25,11 +25,9 @@
#include <cstdlib>
#include <jni.h>
#include <utils/Log.h>
-#include "android/graphics/GraphicsJNI.h"
+#include "GraphicsJNI.h"
#include "graphic_buffer_impl.h"
#include "SkCanvasStateUtils.h"
-#include "SkGraphics.h"
-#include "SkPicture.h"
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index e42ded74acd0..82ea7449bf6d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -84,7 +84,6 @@ public class VerificationActivity extends Activity {
// retrieve data from calling intent
Intent callingIntent = getIntent();
Uri url = callingIntent.getData();
- Bundle extras = callingIntent.getExtras();
if (url != null) {
sVerifiedUrl = url.toString();
@@ -96,7 +95,7 @@ public class VerificationActivity extends Activity {
intent.setData(url);
}
intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
- intent.putExtras(extras);
+ intent.putExtras(callingIntent);
Log.d(TAG, "Starting Installation Service");
startServiceAsUser(intent, UserHandle.SYSTEM);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aad46e9f0959..2dc6f393f7cc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -989,6 +989,11 @@ public class SettingsProvider extends ContentProvider {
String value = setting != null ? setting.getValue() : null;
updateGlobalSetting(Settings.Global.ADB_ENABLED,
value, null, true, userId, true);
+
+ setting = getGlobalSetting(Settings.Global.ADB_WIFI_ENABLED);
+ value = setting != null ? setting.getValue() : null;
+ updateGlobalSetting(Settings.Global.ADB_WIFI_ENABLED,
+ value, null, true, userId, true);
}
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4dc372a39404..0f2ee6ac8bbd 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -111,6 +111,7 @@ public class SettingsBackupTest {
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
Settings.Global.ADB_ALLOWED_CONNECTION_TIME,
Settings.Global.ADB_ENABLED,
+ Settings.Global.ADB_WIFI_ENABLED,
Settings.Global.ADD_USERS_WHEN_LOCKED,
Settings.Global.AIRPLANE_MODE_ON,
Settings.Global.AIRPLANE_MODE_RADIOS,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5458676e1061..f141578f088d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -457,6 +457,25 @@
android:excludeFromRecents="true">
</activity>
+ <!-- started from WirelessDebuggingManager -->
+ <activity android:name=".wifi.WifiDebuggingActivity"
+ android:permission="android.permission.MANAGE_DEBUGGING"
+ android:theme="@style/Theme.SystemUI.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+ <activity-alias
+ android:name=".WifiDebuggingActivityAlias"
+ android:permission="android.permission.DUMP"
+ android:targetActivity=".wifi.WifiDebuggingActivity"
+ android:exported="true">
+ </activity-alias>
+ <activity android:name=".wifi.WifiDebuggingSecondaryUserActivity"
+ android:theme="@style/Theme.SystemUI.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
<!-- started from NetworkPolicyManagerService -->
<activity
android:name=".net.NetworkOverLimitActivity"
@@ -696,8 +715,7 @@
<provider
android:name="com.android.keyguard.clock.ClockOptionsProvider"
android:authorities="com.android.keyguard.clock"
- android:enabled="false"
- android:exported="false"
+ android:exported="true"
android:grantUriPermissions="true">
</provider>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
index 481c4dbe3bf1..a06f434d068c 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_activity.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
@@ -25,6 +25,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bubble_overflow_recycler"
android:layout_gravity="center_horizontal"
+ android:nestedScrollingEnabled="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
@@ -32,6 +33,8 @@
android:id="@+id/bubble_overflow_empty_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingLeft="@dimen/bubble_overflow_empty_state_padding"
+ android:paddingRight="@dimen/bubble_overflow_empty_state_padding"
android:orientation="vertical"
android:gravity="center">
diff --git a/packages/SystemUI/res/layout/bubble_overflow_button.xml b/packages/SystemUI/res/layout/bubble_overflow_button.xml
index eb5dc9b0051a..8f0fd4f37461 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_button.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_button.xml
@@ -14,11 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<ImageView
+<com.android.systemui.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_overflow_button"
android:layout_width="@dimen/individual_bubble_size"
android:layout_height="@dimen/individual_bubble_size"
- android:src="@drawable/ic_bubble_overflow_button"
- android:scaleType="center"
- android:layout_gravity="end"/>
+ android:src="@drawable/ic_bubble_overflow_button"/>
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index 982aa8ef6d16..c2dbacaa64f7 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -19,39 +19,34 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_section_header_height"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:focusable="true"
android:clickable="true"
>
- <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
- android:id="@+id/backgroundNormal"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
- android:id="@+id/backgroundDimmed"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<LinearLayout
android:id="@+id/people_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:gravity="center"
+ android:layout_marginEnd="8dp"
+ android:gravity="bottom"
android:orientation="horizontal">
- <TextView
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/notification_section_header_padding_left"
- android:gravity="start"
- android:textAlignment="gravity"
- android:text="@string/notification_section_header_conversations"
- android:textSize="12sp"
- android:textColor="@color/notification_section_header_label_color"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- />
+ android:gravity="start|center_vertical"
+ android:layout_weight="1">
+
+ <TextView
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_section_header_conversations"
+ />
+
+ </FrameLayout>
<ImageView
android:layout_width="48dp"
@@ -84,16 +79,10 @@
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
- android:layout_marginEnd="8dp"
android:padding="8dp"
android:scaleType="fitCenter"
/>
</LinearLayout>
- <com.android.systemui.statusbar.notification.FakeShadowView
- android:id="@+id/fake_shadow"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
</com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 174a3b8e004b..36ba66af5729 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -25,9 +25,9 @@
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content">
<com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@android:style/Widget.Material.Button.Borderless"
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
android:id="@+id/manage_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -35,10 +35,9 @@
android:focusable="true"
android:contentDescription="@string/accessibility_manage_notification"
android:text="@string/manage_notifications_text"
- android:textColor="?attr/wallpaperTextColor"
- android:textAllCaps="false"/>
+ />
<com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@android:style/Widget.Material.Button.Borderless"
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
android:id="@+id/dismiss_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -46,6 +45,6 @@
android:focusable="true"
android:contentDescription="@string/accessibility_clear_all"
android:text="@string/clear_all_notifications_text"
- android:textColor="?attr/wallpaperTextColor"/>
+ />
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
</com.android.systemui.statusbar.notification.row.FooterView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 508619a27e81..0043d7a7bdad 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -19,32 +19,21 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_section_header_height"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:focusable="true"
android:clickable="true"
>
- <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
- android:id="@+id/backgroundNormal"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.systemui.statusbar.notification.row.NotificationBackgroundView
- android:id="@+id/backgroundDimmed"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<include layout="@layout/status_bar_notification_section_header_contents"/>
</LinearLayout>
- <com.android.systemui.statusbar.notification.FakeShadowView
- android:id="@+id/fake_shadow"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
</com.android.systemui.statusbar.notification.stack.SectionHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
index feabd1c72a65..df4b0471c78b 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
@@ -16,26 +16,30 @@
<!-- Used by both status_bar_notification_header and SectionHeaderView -->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
- <TextView
- android:id="@+id/header_label"
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/notification_section_header_padding_left"
- android:gravity="start"
- android:textAlignment="gravity"
- android:text="@string/notification_section_header_gentle"
- android:textSize="12sp"
- android:textColor="@color/notification_section_header_label_color"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- />
+ android:gravity="start|center_vertical"
+ android:layout_weight="1">
+
+ <TextView
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
+ android:id="@+id/header_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_section_header_gentle"
+ />
+
+ </FrameLayout>
<ImageView
android:id="@+id/btn_clear_all"
- android:layout_width="@dimen/notification_section_header_height"
- android:layout_height="@dimen/notification_section_header_height"
- android:layout_marginEnd="4dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
android:scaleType="center"
+ android:tint="?attr/wallpaperTextColor"
+ android:tintMode="src_in"
+ android:visibility="gone"
/>
</merge>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 15575a49bb5e..1c2404f1921e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -744,7 +744,7 @@
<!-- The top padding of the clear all button -->
<dimen name="clear_all_padding_top">12dp</dimen>
- <dimen name="notification_section_header_height">48dp</dimen>
+ <dimen name="notification_section_header_height">56dp</dimen>
<dimen name="notification_section_header_padding_left">16dp</dimen>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
@@ -1128,8 +1128,10 @@
<dimen name="bubble_padding_top">16dp</dimen>
<!-- Size of individual bubbles. -->
<dimen name="individual_bubble_size">60dp</dimen>
+ <!-- Size of bubble bitmap. -->
+ <dimen name="bubble_bitmap_size">52dp</dimen>
<!-- Size of bubble icon bitmap. -->
- <dimen name="bubble_icon_bitmap_size">52dp</dimen>
+ <dimen name="bubble_overflow_icon_bitmap_size">24dp</dimen>
<!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
<dimen name="bubble_touch_padding">12dp</dimen>
<!-- Size of the circle around the bubbles when they're in the dismiss target. -->
@@ -1141,6 +1143,12 @@
<dimen name="bubble_expanded_view_slop">8dp</dimen>
<!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
+ <!-- Default height of bubble overflow -->
+ <dimen name="bubble_overflow_height">380dp</dimen>
+ <!-- Bubble overflow padding when there are no bubbles -->
+ <dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
+ <!-- Margin of overflow bubbles -->
+ <dimen name="bubble_overflow_margin">16dp</dimen>
<!-- Height of the triangle that points to the expanded bubble -->
<dimen name="bubble_pointer_height">4dp</dimen>
<!-- Width of the triangle that points to the expanded bubble -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5e9feff566e5..4aafec886a37 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -168,6 +168,24 @@
<!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
<string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
+ <!-- Title of confirmation dialog for wireless debugging [CHAR LIMIT=NONE] -->
+ <string name="wifi_debugging_title">Allow wireless debugging on this network?</string>
+
+ <!-- Message of confirmation dialog for wireless debugging [CHAR LIMIT=NONE] -->
+ <string name="wifi_debugging_message">Network Name (SSID)\n<xliff:g id="ssid" example="My wifi">%1$s</xliff:g>\n\nWi\u2011Fi Address (BSSID)\n<xliff:g id="bssid" example="AB:CD:EF:12:34:56">%2$s</xliff:g></string>
+
+ <!-- Option to always allow wireless debugging on this network [CHAR LIMIT=NONE] -->
+ <string name="wifi_debugging_always">Always allow on this network</string>
+
+ <!-- Button label for confirming acceptance of enabling wireless debugging [CHAR LIMIT=15] -->
+ <string name="wifi_debugging_allow">Allow</string>
+
+ <!-- Title of notification shown when trying to enable wireless debugging but a secondary user is the current foreground user. [CHAR LIMIT=NONE] -->
+ <string name="wifi_debugging_secondary_user_title">Wireless debugging not allowed</string>
+
+ <!-- Message of notification shown when trying to enable wireless debugging but a secondary user is the current foreground user. [CHAR LIMIT=NONE] -->
+ <string name="wifi_debugging_secondary_user_message">The user currently signed in to this device can\u2019t turn on wireless debugging. To use this feature, switch to the primary user.</string>
+
<!-- Title of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
<string name="usb_contaminant_title">USB port disabled</string>
@@ -1204,6 +1222,9 @@
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent notifications</string>
+ <!-- Section title for notifications that vibrate or make noise. [CHAR LIMIT=40] -->
+ <string name="notification_section_header_alerting">Alerting notifications</string>
+
<!-- Section title for conversational notifications. [CHAR LIMIT=40] -->
<string name="notification_section_header_conversations">Conversations</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 557e2d65202b..36c4526fb521 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -554,6 +554,14 @@
<item name="android:gravity">center</item>
</style>
+ <style
+ name="TextAppearance.NotificationSectionHeaderButton"
+ parent="@android:style/Widget.Material.Button.Borderless">
+ <item name="android:textColor">?attr/wallpaperTextColor</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
<style name="TextAppearance.HeadsUpStatusBarText"
parent="@*android:style/TextAppearance.DeviceDefault.Notification.Info">
</style>
@@ -661,5 +669,5 @@
<item name="android:textSize">12sp</item>
<item name="android:textColor">@color/control_secondary_text</item>
</style>
-
+
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
new file mode 100644
index 000000000000..b813e2178fa3
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
@@ -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 com.android.systemui.shared.system;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+
+public class WallpaperManagerCompat {
+ private final WallpaperManager mWallpaperManager;
+
+ public WallpaperManagerCompat(Context context) {
+ mWallpaperManager = context.getSystemService(WallpaperManager.class);
+ }
+
+ public void setWallpaperZoomOut(float zoom) {
+ mWallpaperManager.setWallpaperZoomOut(zoom);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e475ef1d9761..6f06f6986c00 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -51,7 +51,7 @@ import javax.inject.Named;
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
- private static final boolean CUSTOM_CLOCKS_ENABLED = false;
+ private static final boolean CUSTOM_CLOCKS_ENABLED = true;
/**
* Animation fraction when text is transitioned to/from bold.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 09d4d5fcbde9..20b1e0d2c822 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -57,6 +57,12 @@ public interface KeyguardSecurityView {
int PROMPT_REASON_PREPARE_FOR_UPDATE = 6;
/**
+ * Primary auth is required because the user uses weak/convenience biometrics and hasn't used
+ * primary auth since a while
+ */
+ int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
+
+ /**
* Interface back to keyguard to tell it when security
* @param callback
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9ba3860f4fb8..f57571d8d4b4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -80,6 +80,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -91,6 +92,7 @@ import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -108,6 +110,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -264,6 +267,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private final Executor mBackgroundExecutor;
/**
* Short delay before restarting biometric authentication after a successful try
@@ -320,12 +324,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
+ private class BiometricAuthenticated {
+ private final boolean mAuthenticated;
+ private final boolean mIsStrongBiometric;
+
+ BiometricAuthenticated(boolean authenticated, boolean isStrongBiometric) {
+ this.mAuthenticated = authenticated;
+ this.mIsStrongBiometric = isStrongBiometric;
+ }
+ }
+
private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray();
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
- private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
- private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray();
+ private SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
+ private SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
@@ -523,10 +537,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
@VisibleForTesting
- protected void onFingerprintAuthenticated(int userId) {
+ protected void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
Assert.isMainThread();
Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
- mUserFingerprintAuthenticated.put(userId, true);
+ mUserFingerprintAuthenticated.put(userId,
+ new BiometricAuthenticated(true, isStrongBiometric));
// Update/refresh trust state only if user can skip bouncer
if (getUserCanSkipBouncer(userId)) {
mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FINGERPRINT);
@@ -536,7 +551,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT);
+ cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT,
+ isStrongBiometric);
}
}
@@ -546,9 +562,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Only authenticate fingerprint once when assistant is visible
mAssistantVisible = false;
+ // Report unlock with strong or non-strong biometric
+ reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+
Trace.endSection();
}
+ private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ mBackgroundExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ }
+ });
+ }
+
private void handleFingerprintAuthFailed() {
Assert.isMainThread();
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -574,7 +602,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
- private void handleFingerprintAuthenticated(int authUserId) {
+ private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
try {
final int userId;
@@ -592,7 +620,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
return;
}
- onFingerprintAuthenticated(userId);
+ onFingerprintAuthenticated(userId, isStrongBiometric);
} finally {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
}
@@ -683,10 +711,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
@VisibleForTesting
- protected void onFaceAuthenticated(int userId) {
+ protected void onFaceAuthenticated(int userId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated");
Assert.isMainThread();
- mUserFaceAuthenticated.put(userId, true);
+ mUserFaceAuthenticated.put(userId,
+ new BiometricAuthenticated(true, isStrongBiometric));
// Update/refresh trust state only if user can skip bouncer
if (getUserCanSkipBouncer(userId)) {
mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE);
@@ -697,7 +726,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onBiometricAuthenticated(userId,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE,
+ isStrongBiometric);
}
}
@@ -707,6 +737,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Only authenticate face once when assistant is visible
mAssistantVisible = false;
+ // Report unlock with strong or non-strong biometric
+ reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+
Trace.endSection();
}
@@ -737,7 +770,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
- private void handleFaceAuthenticated(int authUserId) {
+ private void handleFaceAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
try {
if (mGoingToSleep) {
@@ -760,7 +793,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return;
}
if (DEBUG_FACE) Log.d(TAG, "Face auth succeeded for user " + userId);
- onFaceAuthenticated(userId);
+ onFaceAuthenticated(userId, isStrongBiometric);
} finally {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
@@ -914,9 +947,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
* Returns whether the user is unlocked with biometrics.
*/
public boolean getUserUnlockedWithBiometric(int userId) {
- boolean fingerprintOrFace = mUserFingerprintAuthenticated.get(userId)
- || mUserFaceAuthenticated.get(userId);
- return fingerprintOrFace && isUnlockingWithBiometricAllowed();
+ BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
+ BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
+ boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
+ && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
+ boolean faceAllowed = face != null && face.mAuthenticated
+ && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
+ return fingerprintAllowed || faceAllowed;
}
public boolean getUserTrustIsManaged(int userId) {
@@ -970,8 +1007,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return mUserTrustIsUsuallyManaged.get(userId);
}
- public boolean isUnlockingWithBiometricAllowed() {
- return mStrongAuthTracker.isUnlockingWithBiometricAllowed();
+ public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
+ return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric);
}
public boolean isUserInLockdown(int userId) {
@@ -1169,7 +1206,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
- handleFingerprintAuthenticated(result.getUserId());
+ handleFingerprintAuthenticated(result.getUserId(), result.isStrongBiometric());
Trace.endSection();
}
@@ -1201,7 +1238,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
- handleFaceAuthenticated(result.getUserId());
+ handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
Trace.endSection();
}
@@ -1305,9 +1342,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback;
}
- public boolean isUnlockingWithBiometricAllowed() {
+ public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
int userId = getCurrentUser();
- return isBiometricAllowedForUser(userId);
+ return isBiometricAllowedForUser(isStrongBiometric, userId);
}
public boolean hasUserAuthenticatedSinceBoot() {
@@ -1438,12 +1475,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Context context,
@Main Looper mainLooper,
BroadcastDispatcher broadcastDispatcher,
- DumpController dumpController) {
+ DumpController dumpController,
+ @Background Executor backgroundExecutor) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
dumpController.registerDumpable(this);
+ mBackgroundExecutor = backgroundExecutor;
mHandler = new Handler(mainLooper) {
@Override
@@ -1753,14 +1792,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private boolean shouldListenForFingerprintAssistant() {
+ BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(getCurrentUser());
return mAssistantVisible && mKeyguardOccluded
- && !mUserFingerprintAuthenticated.get(getCurrentUser(), false)
+ && !(fingerprint != null && fingerprint.mAuthenticated)
&& !mUserHasTrust.get(getCurrentUser(), false);
}
private boolean shouldListenForFaceAssistant() {
+ BiometricAuthenticated face = mUserFaceAuthenticated.get(getCurrentUser());
return mAssistantVisible && mKeyguardOccluded
- && !mUserFaceAuthenticated.get(getCurrentUser(), false)
+ && !(face != null && face.mAuthenticated)
&& !mUserHasTrust.get(getCurrentUser(), false);
}
@@ -1817,7 +1858,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
public void onLockIconPressed() {
mLockIconPressed = true;
final int userId = getCurrentUser();
- mUserFaceAuthenticated.put(userId, false);
+ mUserFaceAuthenticated.put(userId, null);
updateFaceListeningState();
mStrongAuthTracker.onStrongAuthRequiredChanged(userId);
}
@@ -2691,9 +2732,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (mFpm != null && mFpm.isHardwareDetected()) {
final int userId = ActivityManager.getCurrentUser();
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+ BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
pw.println(" Fingerprint state (user=" + userId + ")");
- pw.println(" allowed=" + isUnlockingWithBiometricAllowed());
- pw.println(" auth'd=" + mUserFingerprintAuthenticated.get(userId));
+ pw.println(" allowed="
+ + (fingerprint != null
+ && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric)));
+ pw.println(" auth'd=" + (fingerprint != null && fingerprint.mAuthenticated));
pw.println(" authSinceBoot="
+ getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
pw.println(" disabled(DPM)=" + isFingerprintDisabled(userId));
@@ -2706,9 +2750,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
final int userId = ActivityManager.getCurrentUser();
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+ BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
pw.println(" Face authentication state (user=" + userId + ")");
- pw.println(" allowed=" + isUnlockingWithBiometricAllowed());
- pw.println(" auth'd=" + mUserFaceAuthenticated.get(userId));
+ pw.println(" allowed="
+ + (face != null && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric)));
+ pw.println(" auth'd="
+ + (face != null && face.mAuthenticated));
pw.println(" authSinceBoot="
+ getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
pw.println(" disabled(DPM)=" + isFaceDisabled(userId));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 49f72a925a0e..12e0ecd011cf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -239,7 +239,8 @@ public class KeyguardUpdateMonitorCallback {
* @param userId the user id for which the biometric sample was authenticated
* @param biometricSourceType
*/
- public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) { }
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) { }
/**
* Called when biometric authentication provides help string (e.g. "Try again")
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 9cd4aec4617d..03674648d1e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -149,8 +149,6 @@ public final class ClockManager {
LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
- addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
- addBuiltinClock(() -> new AnalogClockController(res, layoutInflater, colorExtractor));
// Store the size of the display for generation of clock preview.
DisplayMetrics dm = res.getDisplayMetrics();
@@ -211,7 +209,8 @@ public final class ClockManager {
return mContentObserver;
}
- private void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
+ @VisibleForTesting
+ void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
ClockPlugin plugin = pluginSupplier.get();
mPreviewClocks.addClockPlugin(plugin);
mBuiltinClocks.add(pluginSupplier);
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index 8503396975b5..85ce313670e3 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -57,7 +57,6 @@ public class CornerHandleView extends View {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(getStrokePx());
- setLayerType(View.LAYER_TYPE_SOFTWARE, mPaint);
final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme);
@@ -118,14 +117,8 @@ public class CornerHandleView extends View {
// Handle color is same as home handle color.
int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
mLightColor, mDarkColor);
- // Shadow color is inverse of handle color.
- int shadowColor = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
- mDarkColor, mLightColor);
if (mPaint.getColor() != color) {
mPaint.setColor(color);
- mPaint.setShadowLayer(/** radius */ getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.assist_handle_shadow_radius), /** shadowDx */ 0,
- /** shadowDy */ 0, /** color */ shadowColor);
if (getVisibility() == VISIBLE && getAlpha() > 0) {
invalidate();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 1a47daceafcc..dc0cb03e9b23 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -96,6 +96,7 @@ public class LatencyTester extends SystemUI {
private void fakeWakeAndUnlock() {
mBiometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
mBiometricUnlockController.onBiometricAuthenticated(
- KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT);
+ KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT,
+ true /* isStrongBiometric */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
index 601bae286451..a1cb7f61ad04 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
@@ -17,7 +17,6 @@ package com.android.systemui.bubbles;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Rect;
@@ -50,9 +49,9 @@ public class BadgedImageView extends ImageView {
// Flyout gets shown before the dot
private int mCurrentDotState = DOT_STATE_SUPPRESSED_FOR_FLYOUT;
- private Bubble mBubble;
+ private BubbleViewProvider mBubble;
- private int mIconBitmapSize;
+ private int mBubbleBitmapSize;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
private boolean mOnLeft;
@@ -78,18 +77,18 @@ public class BadgedImageView extends ImageView {
public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
+ mBubbleBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mDrawParams = new DotRenderer.DrawParams();
Path iconPath = PathParser.createPathFromPathData(
getResources().getString(com.android.internal.R.string.config_icon_mask));
- mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
+ mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
}
/**
* Updates the view with provided info.
*/
- public void update(Bubble bubble) {
+ public void update(BubbleViewProvider bubble) {
mBubble = bubble;
setImageBitmap(bubble.getBadgedImage());
setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
@@ -147,7 +146,7 @@ public class BadgedImageView extends ImageView {
* @param iconPath The new icon path to use when calculating dot position.
*/
void drawDot(Path iconPath) {
- mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
+ mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index cdeb5c3f2511..7ca23085f6ee 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -95,6 +95,7 @@ class Bubble implements BubbleViewProvider {
private int mDotColor;
private Path mDotPath;
+
public static String groupId(NotificationEntry entry) {
UserHandle user = entry.getSbn().getUser();
return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
@@ -111,6 +112,7 @@ class Bubble implements BubbleViewProvider {
mSuppressionListener = listener;
}
+ @Override
public String getKey() {
return mKey;
}
@@ -127,14 +129,17 @@ class Bubble implements BubbleViewProvider {
return mEntry.getSbn().getPackageName();
}
+ @Override
public Bitmap getBadgedImage() {
return mBadgedImage;
}
+ @Override
public int getDotColor() {
return mDotColor;
}
+ @Override
public Path getDotPath() {
return mDotPath;
}
@@ -150,10 +155,12 @@ class Bubble implements BubbleViewProvider {
}
@Nullable
+ @Override
public BadgedImageView getIconView() {
return mIconView;
}
+ @Override
@Nullable
public BubbleExpandedView getExpandedView() {
return mExpandedView;
@@ -240,6 +247,7 @@ class Bubble implements BubbleViewProvider {
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the expanded view in transparent.
*/
+ @Override
public void setContentVisibility(boolean visibility) {
if (mExpandedView != null) {
mExpandedView.setContentVisibility(visibility);
@@ -333,7 +341,8 @@ class Bubble implements BubbleViewProvider {
/**
* Whether the bubble for this notification should show a dot indicating updated content.
*/
- boolean showDot() {
+ @Override
+ public boolean showDot() {
return mShowBubbleUpdateDot
&& !mEntry.shouldSuppressNotificationDot()
&& !shouldSuppressNotification();
@@ -484,6 +493,7 @@ class Bubble implements BubbleViewProvider {
return Objects.hash(mKey);
}
+ @Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index) {
if (this.getEntry() == null
|| this.getEntry().getSbn() == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index fe191f40d31f..e3983c5b2d92 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -94,6 +94,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
private Point mDisplaySize;
private int mMinHeight;
+ private int mOverflowHeight;
private int mSettingsIconHeight;
private int mPointerWidth;
private int mPointerHeight;
@@ -218,6 +219,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
Resources res = getResources();
mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
+ mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mExpandedViewTouchSlop = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_slop);
}
@@ -420,20 +422,19 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
return true;
}
- // TODO(138116789) Fix overflow height.
void updateHeight() {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
}
if (usingActivityView()) {
- float desiredHeight = mMinHeight;
+ float desiredHeight = mOverflowHeight;
if (!mIsOverflow) {
desiredHeight = Math.max(mBubble.getDesiredHeight(mContext), mMinHeight);
}
float height = Math.min(desiredHeight, getMaxExpandedHeight());
- height = Math.max(height, mMinHeight);
+ height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
- mNeedsNewHeight = lp.height != height;
+ mNeedsNewHeight = lp.height != height;
if (!mKeyboardVisible) {
// If the keyboard is visible... don't adjust the height because that will cause
// a configuration change and the keyboard will be lost.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 5b9ea7dd5e3a..ca53fa7e6811 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -58,7 +58,7 @@ public class BubbleFlyoutView extends FrameLayout {
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
private final int mBubbleSize;
- private final int mBubbleIconBitmapSize;
+ private final int mBubbleBitmapSize;
private final float mBubbleIconTopPadding;
private final int mFlyoutElevation;
@@ -156,13 +156,13 @@ public class BubbleFlyoutView extends FrameLayout {
mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
- mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
- mBubbleIconTopPadding = (mBubbleSize - mBubbleIconBitmapSize) / 2f;
+ mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
+ mBubbleIconTopPadding = (mBubbleSize - mBubbleBitmapSize) / 2f;
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mFlyoutElevation = res.getDimensionPixelSize(R.dimen.bubble_flyout_elevation);
- mOriginalDotSize = SIZE_PERCENTAGE * mBubbleIconBitmapSize;
+ mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize;
mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
mNewDotSize = mNewDotRadius * 2f;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index 6cf1086e70be..a0e744979112 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -17,18 +17,23 @@
package com.android.systemui.bubbles;
import static android.view.View.GONE;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.InsetDrawable;
+import android.util.PathParser;
+import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.systemui.R;
@@ -37,15 +42,24 @@ import com.android.systemui.R;
* Class for showing aged out bubbles.
*/
public class BubbleOverflow implements BubbleViewProvider {
+ public static final String KEY = "Overflow";
- private ImageView mOverflowBtn;
+ private BadgedImageView mOverflowBtn;
private BubbleExpandedView mOverflowExpandedView;
private LayoutInflater mInflater;
private Context mContext;
+ private Bitmap mIcon;
+ private Path mPath;
+ private int mBitmapSize;
+ private int mIconBitmapSize;
+ private int mDotColor;
public BubbleOverflow(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
+ mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
+ mIconBitmapSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.bubble_overflow_icon_bitmap_size);
}
public void setUpOverflow(ViewGroup parentViewGroup) {
@@ -54,12 +68,49 @@ public class BubbleOverflow implements BubbleViewProvider {
false /* attachToRoot */);
mOverflowExpandedView.setOverflow(true);
- mOverflowBtn = (ImageView) mInflater.inflate(R.layout.bubble_overflow_button,
+ updateIcon(mContext, parentViewGroup);
+ }
+
+ // TODO(b/149146374) Propagate theme change to bubbles in overflow.
+ void updateIcon(Context context, ViewGroup parentViewGroup) {
+ mInflater = LayoutInflater.from(context);
+ mOverflowBtn = (BadgedImageView) mInflater.inflate(R.layout.bubble_overflow_button,
parentViewGroup /* root */,
false /* attachToRoot */);
- setOverflowBtnTheme();
+ TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{android.R.attr.colorBackgroundFloating});
+ int bgColor = ta.getColor(0, Color.WHITE /* default */);
+ ta.recycle();
+
+ TypedValue typedValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+ int colorAccent = mContext.getColor(typedValue.resourceId);
+ mOverflowBtn.getDrawable().setTint(colorAccent);
+ mDotColor = colorAccent;
+
+ ColorDrawable bg = new ColorDrawable(bgColor);
+ InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(),
+ mBitmapSize - mIconBitmapSize /* inset */);
+ AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(bg, fg);
+
+ BubbleIconFactory iconFactory = new BubbleIconFactory(context);
+ mIcon = iconFactory.createBadgedIconBitmap(adaptiveIconDrawable,
+ null /* user */,
+ true /* shrinkNonAdaptiveIcons */).icon;
+
+ float scale = iconFactory.getNormalizer().getScale(mOverflowBtn.getDrawable(),
+ null /* outBounds */, null /* path */, null /* outMaskShape */);
+ float radius = DEFAULT_PATH_SIZE / 2f;
+ mPath = PathParser.createPathFromPathData(
+ context.getResources().getString(com.android.internal.R.string.config_icon_mask));
+ Matrix matrix = new Matrix();
+ matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+ radius /* pivot y */);
+ mPath.transform(matrix);
+
mOverflowBtn.setVisibility(GONE);
+ mOverflowBtn.update(this);
}
ImageView getBtn() {
@@ -70,38 +121,49 @@ public class BubbleOverflow implements BubbleViewProvider {
mOverflowBtn.setVisibility(visible);
}
- // TODO(b/149146374) Propagate theme change to bubbles in overflow.
- void setOverflowBtnTheme() {
- TypedArray ta = mContext.obtainStyledAttributes(
- new int[]{android.R.attr.colorBackgroundFloating});
- int bgColor = ta.getColor(0, Color.WHITE /* default */);
- ta.recycle();
+ @Override
+ public BubbleExpandedView getExpandedView() {
+ return mOverflowExpandedView;
+ }
- InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(), 28);
- ColorDrawable bg = new ColorDrawable(bgColor);
- AdaptiveIconDrawable adaptiveIcon = new AdaptiveIconDrawable(bg, fg);
- mOverflowBtn.setImageDrawable(adaptiveIcon);
+ @Override
+ public int getDotColor() {
+ return mDotColor;
}
+ @Override
+ public Bitmap getBadgedImage() {
+ return mIcon;
+ }
- public BubbleExpandedView getExpandedView() {
- return mOverflowExpandedView;
+ @Override
+ public boolean showDot() {
+ return false;
+ }
+
+ @Override
+ public Path getDotPath() {
+ return mPath;
}
+ @Override
public void setContentVisibility(boolean visible) {
mOverflowExpandedView.setContentVisibility(visible);
}
+ @Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY,
int index) {
// TODO(b/149133814) Log overflow UI events.
}
+ @Override
public View getIconView() {
return mOverflowBtn;
}
+ @Override
public String getKey() {
- return BubbleOverflowActivity.KEY;
+ return BubbleOverflow.KEY;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index eb836b1a21f9..7636c6712e41 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -29,7 +29,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -47,7 +46,6 @@ import javax.inject.Inject;
* Must be public to be accessible to androidx...AppComponentFactory
*/
public class BubbleOverflowActivity extends Activity {
- public static final String KEY = "Overflow";
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowActivity" : TAG_BUBBLES;
private LinearLayout mEmptyState;
@@ -73,10 +71,10 @@ public class BubbleOverflowActivity extends Activity {
new GridLayoutManager(getApplicationContext(),
getResources().getInteger(R.integer.bubbles_overflow_columns)));
+ int bubbleMargin = getResources().getDimensionPixelSize(R.dimen.bubble_overflow_margin);
mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
- mBubbleController::promoteBubbleFromOverflow);
+ mBubbleController::promoteBubbleFromOverflow, bubbleMargin);
mRecyclerView.setAdapter(mAdapter);
-
onDataChanged(mBubbleController.getOverflowBubbles());
mBubbleController.setOverflowCallback(() -> {
onDataChanged(mBubbleController.getOverflowBubbles());
@@ -141,10 +139,13 @@ public class BubbleOverflowActivity extends Activity {
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
+ private int mBubbleMargin;
- public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble) {
+ public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble,
+ int bubbleMargin) {
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
+ mBubbleMargin = bubbleMargin;
}
@Override
@@ -152,6 +153,12 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
int viewType) {
BadgedImageView view = (BadgedImageView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.bubble_view, parent, false);
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ );
+ params.setMargins(mBubbleMargin, mBubbleMargin, mBubbleMargin, mBubbleMargin);
+ view.setLayoutParams(params);
return new ViewHolder(view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 955edcf6acb9..072c20c684dd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -410,13 +410,7 @@ public class BubbleStackView extends FrameLayout {
setFocusable(true);
mBubbleContainer.bringToFront();
- mBubbleOverflow = new BubbleOverflow(mContext);
- if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
- mBubbleOverflow.setUpOverflow(this);
- mBubbleContainer.addView(mBubbleOverflow.getBtn(), 0,
- new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-
- }
+ setUpOverflow();
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
if (!mIsExpanded || mIsExpansionAnimating) {
@@ -525,14 +519,29 @@ public class BubbleStackView extends FrameLayout {
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
+ private void setUpOverflow() {
+ if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+ return;
+ }
+ int overflowBtnIndex = 0;
+ if (mBubbleOverflow == null) {
+ mBubbleOverflow = new BubbleOverflow(mContext);
+ mBubbleOverflow.setUpOverflow(this);
+ } else {
+ mBubbleContainer.removeView(mBubbleOverflow.getBtn());
+ mBubbleOverflow.updateIcon(mContext, this);
+ overflowBtnIndex = mBubbleContainer.getChildCount() - 1;
+ }
+ mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
+ new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+
+ }
/**
* Handle theme changes.
*/
public void onThemeChanged() {
setUpFlyout();
- if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
- mBubbleOverflow.setOverflowBtnTheme();
- }
+ setUpOverflow();
}
/** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
@@ -726,7 +735,7 @@ public class BubbleStackView extends FrameLayout {
if (mExpandedBubble == null
|| (BubbleExperimentConfig.allowBubbleOverflow(mContext)
&& mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
- && mExpandedBubble.getKey() == BubbleOverflowActivity.KEY)) {
+ && mExpandedBubble.getKey() == BubbleOverflow.KEY)) {
return null;
}
return (Bubble) mExpandedBubble;
@@ -1651,7 +1660,7 @@ public class BubbleStackView extends FrameLayout {
* is between 0 and the bubble count minus 1.
*/
int getBubbleIndex(@Nullable BubbleViewProvider provider) {
- if (provider == null || provider.getKey() == BubbleOverflowActivity.KEY) {
+ if (provider == null || provider.getKey() == BubbleOverflow.KEY) {
return 0;
}
Bubble b = (Bubble) provider;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 645696d0bcac..5e3e747ad2c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -100,9 +100,6 @@ class BubbleTouchHandler implements View.OnTouchListener {
&& !(mTouchedView instanceof BubbleStackView)
&& !(mTouchedView instanceof BubbleFlyoutView)) {
- if (mTouchedView.getId() == R.id.bubble_overflow_button) {
- mStack.showOverflow();
- }
// Not touching anything touchable, but we shouldn't collapse (e.g. touching edge
// of expanded view).
resetForNextGesture();
@@ -225,9 +222,12 @@ class BubbleTouchHandler implements View.OnTouchListener {
mBubbleData.setExpanded(!mBubbleData.isExpanded());
} else {
final String key = ((BadgedImageView) mTouchedView).getKey();
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
+ if (key == BubbleOverflow.KEY) {
+ mStack.showOverflow();
+ } else {
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
+ }
}
-
resetForNextGesture();
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
index 59fc435222d6..f04933abdcc2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
@@ -16,6 +16,8 @@
package com.android.systemui.bubbles;
+import android.graphics.Bitmap;
+import android.graphics.Path;
import android.view.View;
/**
@@ -23,8 +25,20 @@ import android.view.View;
*/
interface BubbleViewProvider {
BubbleExpandedView getExpandedView();
+
void setContentVisibility(boolean visible);
+
View getIconView();
+
void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index);
+
String getKey();
+
+ Bitmap getBadgedImage();
+
+ int getDotColor();
+
+ Path getDotPath();
+
+ boolean showDot();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 60c8c4e10cf0..245d4afbf015 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -157,7 +157,7 @@ public class StackAnimationController extends
/** Horizontal offset of bubbles in the stack. */
private float mStackOffset;
/** Diameter of the bubble icon. */
- private int mBubbleIconBitmapSize;
+ private int mBubbleBitmapSize;
/** Width of the bubble (icon and padding). */
private int mBubbleSize;
/**
@@ -263,7 +263,7 @@ public class StackAnimationController extends
return false;
}
- float stackCenter = mStackPosition.x + mBubbleIconBitmapSize / 2;
+ float stackCenter = mStackPosition.x + mBubbleBitmapSize / 2;
float screenCenter = mLayout.getWidth() / 2;
return stackCenter < screenCenter;
}
@@ -306,7 +306,7 @@ public class StackAnimationController extends
* @return The X value that the stack will end up at after the fling/spring.
*/
public float flingStackThenSpringToEdge(float x, float velX, float velY) {
- final boolean stackOnLeftSide = x - mBubbleIconBitmapSize / 2 < mLayout.getWidth() / 2;
+ final boolean stackOnLeftSide = x - mBubbleBitmapSize / 2 < mLayout.getWidth() / 2;
final boolean stackShouldFlingLeft = stackOnLeftSide
? velX < ESCAPE_VELOCITY
@@ -642,7 +642,7 @@ public class StackAnimationController extends
new SpringForce()
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_MEDIUM),
- velX, mLayout.getWidth() / 2f - mBubbleIconBitmapSize / 2f);
+ velX, mLayout.getWidth() / 2f - mBubbleBitmapSize / 2f);
springFirstBubbleWithStackFollowing(
DynamicAnimation.TRANSLATION_Y,
@@ -809,7 +809,7 @@ public class StackAnimationController extends
Resources res = layout.getResources();
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
- mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
+ mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
mStackStartingVerticalOffset =
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 6a64c8386798..f719cc65be71 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -130,7 +130,8 @@ public class FalsingManagerImpl implements FalsingManager {
new KeyguardUpdateMonitorCallback() {
@Override
public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType) {
+ BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
if (userId == KeyguardUpdateMonitor.getCurrentUser()
&& biometricSourceType == BiometricSourceType.FACE) {
mJustUnlockedWithFace = true;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 2f3e3364a50a..a084ae6ed50f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -78,7 +78,8 @@ public class BrightLineFalsingManager implements FalsingManager {
new KeyguardUpdateMonitorCallback() {
@Override
public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType) {
+ BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
if (userId == KeyguardUpdateMonitor.getCurrentUser()
&& biometricSourceType == BiometricSourceType.FACE) {
mJustUnlockedWithFace = true;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 374153ce2409..2e6c9559d696 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -22,6 +22,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BA
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -538,7 +539,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
}
@Override
- public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
if (mLockPatternUtils.isSecure(userId)) {
mLockPatternUtils.getDevicePolicyManager().reportSuccessfulBiometricAttempt(
userId);
@@ -675,6 +677,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE) != 0) {
return KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
+ } else if (any && (strongAuth
+ & STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT) != 0) {
+ return KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
}
return KeyguardSecurityView.PROMPT_REASON_NONE;
}
@@ -1842,6 +1847,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show();
+
+ // schedule 4hr idle timeout after which non-strong biometrics (i.e. weak or convenience
+ // biometric) can't be used to unlock device until unlocking with strong biometric or
+ // primary auth (i.e. PIN/pattern/password)
+ mLockPatternUtils.scheduleNonStrongBiometricIdleTimeout(
+ KeyguardUpdateMonitor.getCurrentUser());
+
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 187a3bdec13f..4f9052709870 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -59,6 +59,7 @@ public class UserDetailView extends PseudoGridView {
private final Context mContext;
protected UserSwitcherController mController;
+ private View mCurrentUserView;
public Adapter(Context context, UserSwitcherController controller) {
super(controller);
@@ -89,6 +90,9 @@ public class UserDetailView extends PseudoGridView {
v.bind(name, item.picture, item.info.id);
}
v.setActivated(item.isCurrent);
+ if (item.isCurrent) {
+ mCurrentUserView = v;
+ }
v.setDisabledByAdmin(item.isDisabledByAdmin);
if (!item.isSwitchToEnabled) {
v.setEnabled(false);
@@ -107,6 +111,12 @@ public class UserDetailView extends PseudoGridView {
mController.startActivity(intent);
} else if (tag.isSwitchToEnabled) {
MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
+ if (!tag.isAddUser && !tag.isRestricted && !tag.isDisabledByAdmin) {
+ if (mCurrentUserView != null) {
+ mCurrentUserView.setActivated(false);
+ }
+ view.setActivated(true);
+ }
switchTo(tag);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9e1e347da5e0..f06cd54f7756 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -497,9 +497,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
flashOutAnimator.addUpdateListener(animation ->
mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));
- final PointF startPos = new PointF((float) bounds.left, (float) bounds.top);
- final PointF finalPos = new PointF(mScreenshotOffsetXPx,
- mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale);
+ final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
+ final PointF finalPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f,
+ mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f);
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
@@ -517,11 +517,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
}
if (t < xPositionPct) {
- mScreenshotView.setX(MathUtils.lerp(
- startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)));
+ float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
+ mFastOutSlowIn.getInterpolation(t / xPositionPct));
+ mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f);
}
- mScreenshotView.setY(MathUtils.lerp(
- startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)));
+ float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
+ mFastOutSlowIn.getInterpolation(t));
+ mScreenshotView.setY(yCenter - height * mScreenshotView.getScaleY() / 2f);
});
toCorner.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 7de70f5f0087..25715212a344 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -281,7 +281,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
.putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
.putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
mSmartActionsEnabled)
- .setAction(Intent.ACTION_SEND),
+ .setAction(Intent.ACTION_SEND)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
@@ -310,7 +311,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
.putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
.putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
mSmartActionsEnabled)
- .setAction(Intent.ACTION_EDIT),
+ .setAction(Intent.ACTION_EDIT)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
@@ -324,7 +326,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
.putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString())
.putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId)
.putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED,
- mSmartActionsEnabled),
+ mSmartActionsEnabled)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
Icon.createWithResource(r, R.drawable.ic_screenshot_delete),
@@ -361,9 +364,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
String actionType = extras.getString(
ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
- Intent intent = new Intent(context,
- GlobalScreenshot.SmartActionsReceiver.class).putExtra(
- GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent);
+ Intent intent = new Intent(context, GlobalScreenshot.SmartActionsReceiver.class)
+ .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, action.actionIntent)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
mRandom.nextInt(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index ab69d477c2ee..4bb8621f9988 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -90,7 +90,7 @@ open class BlurUtils @Inject constructor(
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
- IndentingPrintWriter(pw, " ").use {
+ IndentingPrintWriter(pw, " ").let {
it.println("BlurUtils:")
it.increaseIndent()
it.println("minBlurRadius: $minBlurRadius")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7d3d4061014b..4f8e6cfdf767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -645,7 +645,13 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onBiometricHelp(int msgId, String helpString,
BiometricSourceType biometricSourceType) {
- if (!mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()) {
+ // TODO(b/141025588): refactor to reduce repetition of code/comments
+ // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+ // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+ // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+ // check of whether non-strong biometric is allowed
+ if (!mKeyguardUpdateMonitor
+ .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
return;
}
boolean showSwipeToUnlock =
@@ -705,13 +711,21 @@ public class KeyguardIndicationController implements StateListener,
private boolean shouldSuppressFingerprintError(int msgId,
KeyguardUpdateMonitor updateMonitor) {
- return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+ // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+ // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+ // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+ // check of whether non-strong biometric is allowed
+ return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
&& msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
|| msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
}
private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
- return ((!updateMonitor.isUnlockingWithBiometricAllowed()
+ // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+ // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+ // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+ // check of whether non-strong biometric is allowed
+ return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
&& msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
|| msgId == FaceManager.FACE_ERROR_CANCELED);
}
@@ -745,8 +759,9 @@ public class KeyguardIndicationController implements StateListener,
}
@Override
- public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
- super.onBiometricAuthenticated(userId, biometricSourceType);
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index 009551168010..48386dce5d3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -22,6 +22,7 @@ import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
import com.android.systemui.util.DeviceConfigProxy
@@ -45,7 +46,7 @@ class NotificationSectionsFeatureManager @Inject constructor(
fun getNotificationBuckets(): IntArray {
return when {
isFilteringEnabled() ->
- intArrayOf(BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
+ intArrayOf(BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
NotificationUtils.useNewInterruptionModel(context) ->
intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
else ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index e612c07ac18a..9c942a52b966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -28,6 +28,7 @@ import com.android.systemui.statusbar.notification.NotificationSectionsFeatureMa
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -90,12 +91,12 @@ open class NotificationRankingManager @Inject constructor(
val bIsHighPriority = b.isHighPriority()
when {
- usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
- usePeopleFiltering && aIsImportantPeople != bIsImportantPeople ->
- if (aIsImportantPeople) -1 else 1
aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
// Provide consistent ranking with headsUpManager
aHeadsUp -> headsUpManager.compare(a, b)
+ usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
+ usePeopleFiltering && aIsImportantPeople != bIsImportantPeople ->
+ if (aIsImportantPeople) -1 else 1
// Upsort current media notification.
aMedia != bMedia -> if (aMedia) -1 else 1
// Upsort PRIORITY_MAX system notifications
@@ -162,7 +163,9 @@ open class NotificationRankingManager @Inject constructor(
isMedia: Boolean,
isSystemMax: Boolean
) {
- if (usePeopleFiltering && entry.isPeopleNotification()) {
+ if (usePeopleFiltering && isHeadsUp) {
+ entry.bucket = BUCKET_HEADS_UP
+ } else if (usePeopleFiltering && entry.isPeopleNotification()) {
entry.bucket = BUCKET_PEOPLE
} else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) {
entry.bucket = BUCKET_ALERTING
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
index efcef7124035..16574abab7aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
@@ -24,8 +24,8 @@ abstract class PeopleHubModule {
@Binds
abstract fun peopleHubSectionFooterViewAdapter(
- impl: PeopleHubSectionFooterViewAdapterImpl
- ): PeopleHubSectionFooterViewAdapter
+ impl: PeopleHubViewAdapterImpl
+ ): PeopleHubViewAdapter
@Binds
abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index ec1d6deb1b8f..e28d03fc8b42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -25,17 +25,16 @@ import android.provider.Settings
import android.view.View
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager
import javax.inject.Inject
import javax.inject.Singleton
/** Boundary between the View and PeopleHub, as seen by the View. */
-interface PeopleHubSectionFooterViewAdapter {
- fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary)
+interface PeopleHubViewAdapter {
+ fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription
}
-/** Abstract `View` representation of PeopleHub footer in [NotificationSectionsManager]. */
-interface PeopleHubSectionFooterViewBoundary {
+/** Abstract `View` representation of PeopleHub. */
+interface PeopleHubViewBoundary {
/** View used for animating the activity launch caused by clicking a person in the hub. */
val associatedViewForClickAnimation: View
@@ -57,23 +56,22 @@ interface PeopleHubViewModelFactory {
}
/**
- * Wraps a [PeopleHubSectionFooterViewBoundary] in a [DataListener], and connects it to the data
+ * Wraps a [PeopleHubViewBoundary] in a [DataListener], and connects it to the data
* pipeline.
*
* @param dataSource PeopleHub data pipeline.
*/
@Singleton
-class PeopleHubSectionFooterViewAdapterImpl @Inject constructor(
+class PeopleHubViewAdapterImpl @Inject constructor(
private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubViewModelFactory>
-) : PeopleHubSectionFooterViewAdapter {
+) : PeopleHubViewAdapter {
- override fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) {
- dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
- }
+ override fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription =
+ dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
}
private class PeopleHubDataListenerImpl(
- private val viewBoundary: PeopleHubSectionFooterViewBoundary
+ private val viewBoundary: PeopleHubViewBoundary
) : DataListener<PeopleHubViewModelFactory> {
override fun onDataChanged(data: PeopleHubViewModelFactory) {
@@ -92,7 +90,7 @@ private class PeopleHubDataListenerImpl(
* Converts [PeopleHubModel]s into [PeopleHubViewModelFactory]s.
*
* This class serves as the glue between the View layer (which depends on
- * [PeopleHubSectionFooterViewBoundary]) and the Data layer (which produces [PeopleHubModel]s).
+ * [PeopleHubViewBoundary]) and the Data layer (which produces [PeopleHubModel]s).
*/
@Singleton
class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index a0fef0068b05..e79d89f3a45c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -67,29 +67,34 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int givenHeight = MeasureSpec.getSize(heightMeasureSpec);
final int viewHorizontalPadding = getPaddingStart() + getPaddingEnd();
+
+ // Max height is as large as possible, unless otherwise requested
int ownMaxHeight = Integer.MAX_VALUE;
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
- ownMaxHeight = Math.min(givenSize, ownMaxHeight);
+ if (heightMode != MeasureSpec.UNSPECIFIED && givenHeight != 0) {
+ // Set our max height to what was requested from the parent
+ ownMaxHeight = Math.min(givenHeight, ownMaxHeight);
}
- int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+
+ // height of the largest child
int maxChildHeight = 0;
+ int atMostOwnMaxHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
- int childHeightSpec = newHeightSpec;
+ int childHeightSpec = atMostOwnMaxHeightSpec;
ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
if (layoutParams.height >= 0) {
- // An actual height is set
- childHeightSpec = layoutParams.height > ownMaxHeight
- ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
- : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
+ // If an actual height is set, cap it to the max height
+ childHeightSpec = MeasureSpec.makeMeasureSpec(
+ Math.min(layoutParams.height, ownMaxHeight),
+ MeasureSpec.EXACTLY);
}
child.measure(getChildMeasureSpec(
widthMeasureSpec, viewHorizontalPadding, layoutParams.width),
@@ -100,15 +105,22 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
mMatchParentViews.add(child);
}
}
+
+ // Set our own height to the given height, or the height of the largest child
int ownHeight = heightMode == MeasureSpec.EXACTLY
- ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
- newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
+ ? givenHeight
+ : Math.min(ownMaxHeight, maxChildHeight);
+ int exactlyOwnHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
+
+ // Now that we know our own height, measure the children that are MATCH_PARENT
for (View child : mMatchParentViews) {
child.measure(getChildMeasureSpec(
widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width),
- newHeightSpec);
+ exactlyOwnHeightSpec);
}
mMatchParentViews.clear();
+
+ // Finish up
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, ownHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 23433cb1682d..b3561c2deda7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -16,11 +16,10 @@
package com.android.systemui.statusbar.notification.stack;
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
-
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
@@ -35,18 +34,21 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.people.DataListener;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewBoundary;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewBoundary;
import com.android.systemui.statusbar.notification.people.PersonViewModel;
+import com.android.systemui.statusbar.notification.people.Subscription;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import javax.inject.Inject;
@@ -63,63 +65,65 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
private static final String TAG = "NotifSectionsManager";
private static final boolean DEBUG = false;
- private NotificationStackScrollLayout mParent;
private final ActivityStarter mActivityStarter;
private final StatusBarStateController mStatusBarStateController;
private final ConfigurationController mConfigurationController;
- private final int mNumberOfSections;
+ private final PeopleHubViewAdapter mPeopleHubViewAdapter;
private final NotificationSectionsFeatureManager mSectionsFeatureManager;
- private final NotificationRowComponent.Builder mNotificationRowComponentBuilder;
- private boolean mInitialized = false;
-
- private SectionHeaderView mGentleHeader;
- private boolean mGentleHeaderVisible = false;
+ private final int mNumberOfSections;
- private boolean mPeopleHubVisible = false;
- private PeopleHubView mPeopleHubView;
- private final PeopleHubSectionFooterViewAdapter mPeopleHubViewAdapter;
- private final PeopleHubSectionFooterViewBoundary mPeopleHubViewBoundary =
- new PeopleHubSectionFooterViewBoundary() {
- @Override
- public void setVisible(boolean isVisible) {
- if (mPeopleHubVisible != isVisible) {
- mPeopleHubVisible = isVisible;
- if (mInitialized) {
- updateSectionBoundaries();
- }
- }
+ private final PeopleHubViewBoundary mPeopleHubViewBoundary = new PeopleHubViewBoundary() {
+ @Override
+ public void setVisible(boolean isVisible) {
+ if (mPeopleHubVisible != isVisible) {
+ mPeopleHubVisible = isVisible;
+ if (mInitialized) {
+ updateSectionBoundaries();
}
+ }
+ }
- @NonNull
- @Override
- public View getAssociatedViewForClickAnimation() {
- return mPeopleHubView;
- }
+ @NonNull
+ @Override
+ public View getAssociatedViewForClickAnimation() {
+ return mPeopleHubView;
+ }
- @NonNull
- @Override
- public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() {
- return mPeopleHubView.getPersonViewAdapters();
- }
- };
+ @NonNull
+ @Override
+ public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() {
+ return mPeopleHubView.getPersonViewAdapters();
+ }
+ };
+
+ private NotificationStackScrollLayout mParent;
+ private boolean mInitialized = false;
+ private SectionHeaderView mGentleHeader;
+ private boolean mGentleHeaderVisible;
@Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
+ private SectionHeaderView mAlertingHeader;
+ private boolean mAlertingHeaderVisible;
+
+ private PeopleHubView mPeopleHubView;
+ private boolean mPeopleHeaderVisible;
+ private boolean mPeopleHubVisible = false;
+ @Nullable private Subscription mPeopleHubSubscription;
+
@Inject
NotificationSectionsManager(
ActivityStarter activityStarter,
StatusBarStateController statusBarStateController,
ConfigurationController configurationController,
- PeopleHubSectionFooterViewAdapter peopleHubViewAdapter,
- NotificationSectionsFeatureManager sectionsFeatureManager,
- NotificationRowComponent.Builder notificationRowComponentBuilder) {
+ PeopleHubViewAdapter peopleHubViewAdapter,
+ NotificationSectionsFeatureManager sectionsFeatureManager) {
mActivityStarter = activityStarter;
mStatusBarStateController = statusBarStateController;
mConfigurationController = configurationController;
mPeopleHubViewAdapter = peopleHubViewAdapter;
mSectionsFeatureManager = sectionsFeatureManager;
mNumberOfSections = mSectionsFeatureManager.getNumberOfBuckets();
- mNotificationRowComponentBuilder = notificationRowComponentBuilder;
}
NotificationSection[] createSectionsForBuckets() {
@@ -141,105 +145,81 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
mInitialized = true;
mParent = parent;
reinflateViews(layoutInflater);
- mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
mConfigurationController.addCallback(mConfigurationListener);
}
- /**
- * Reinflates the entire notification header, including all decoration views.
- */
- void reinflateViews(LayoutInflater layoutInflater) {
- int oldGentleHeaderPos = -1;
- int oldPeopleHubPos = -1;
- if (mGentleHeader != null) {
- if (mGentleHeader.getTransientContainer() != null) {
- mGentleHeader.getTransientContainer().removeView(mGentleHeader);
- } else if (mGentleHeader.getParent() != null) {
- oldGentleHeaderPos = mParent.indexOfChild(mGentleHeader);
- mParent.removeView(mGentleHeader);
+ private <T extends ExpandableView> T reinflateView(
+ T view, LayoutInflater layoutInflater, @LayoutRes int layoutResId) {
+ int oldPos = -1;
+ if (view != null) {
+ if (view.getTransientContainer() != null) {
+ view.getTransientContainer().removeView(mGentleHeader);
+ } else if (view.getParent() != null) {
+ oldPos = mParent.indexOfChild(view);
+ mParent.removeView(view);
}
}
- if (mPeopleHubView != null) {
- if (mPeopleHubView.getTransientContainer() != null) {
- mPeopleHubView.getTransientContainer().removeView(mPeopleHubView);
- } else if (mPeopleHubView.getParent() != null) {
- oldPeopleHubPos = mParent.indexOfChild(mPeopleHubView);
- mParent.removeView(mPeopleHubView);
- }
+
+ view = (T) layoutInflater.inflate(layoutResId, mParent, false);
+
+ if (oldPos != -1) {
+ mParent.addView(view, oldPos);
}
- mGentleHeader = (SectionHeaderView) layoutInflater.inflate(
- R.layout.status_bar_notification_section_header, mParent, false);
- NotificationRowComponent sectionHeaderComponent = mNotificationRowComponentBuilder
- .activatableNotificationView(mGentleHeader)
- .build();
- sectionHeaderComponent.getActivatableNotificationViewController().init();
+ return view;
+ }
+ /**
+ * Reinflates the entire notification header, including all decoration views.
+ */
+ void reinflateViews(LayoutInflater layoutInflater) {
+ mGentleHeader = reinflateView(
+ mGentleHeader, layoutInflater, R.layout.status_bar_notification_section_header);
+ mGentleHeader.setHeaderText(R.string.notification_section_header_gentle);
mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick);
- if (oldGentleHeaderPos != -1) {
- mParent.addView(mGentleHeader, oldGentleHeaderPos);
- }
-
- mPeopleHubView = (PeopleHubView) layoutInflater.inflate(
- R.layout.people_strip, mParent, false);
+ mAlertingHeader = reinflateView(
+ mAlertingHeader, layoutInflater, R.layout.status_bar_notification_section_header);
+ mAlertingHeader.setHeaderText(R.string.notification_section_header_alerting);
+ mAlertingHeader.setOnHeaderClickListener(this::onGentleHeaderClick);
- NotificationRowComponent notificationRowComponent = mNotificationRowComponentBuilder
- .activatableNotificationView(mPeopleHubView)
- .build();
- notificationRowComponent.getActivatableNotificationViewController().init();
-
- if (oldPeopleHubPos != -1) {
- mParent.addView(mPeopleHubView, oldPeopleHubPos);
+ if (mPeopleHubSubscription != null) {
+ mPeopleHubSubscription.unsubscribe();
}
+ mPeopleHubView = reinflateView(mPeopleHubView, layoutInflater, R.layout.people_strip);
+ mPeopleHubSubscription = mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
}
- /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */
+ /** Listener for when the "clear all" button is clicked on the gentle notification header. */
void setOnClearGentleNotifsClickListener(View.OnClickListener listener) {
mOnClearGentleNotifsClickListener = listener;
}
- /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
- void onUiModeChanged() {
- mGentleHeader.onUiModeChanged();
- }
-
@Override
public boolean beginsSection(@NonNull View view, @Nullable View previous) {
- boolean begin = false;
- if (view instanceof ActivatableNotificationView) {
- if (previous instanceof ActivatableNotificationView) {
- // If we're drawing the first non-person notification, break out a section
- ActivatableNotificationView curr = (ActivatableNotificationView) view;
- ActivatableNotificationView prev = (ActivatableNotificationView) previous;
-
- begin = getBucket(curr) != getBucket(prev);
- }
- }
-
- if (!begin) {
- begin = view == mGentleHeader || view == mPeopleHubView;
- }
-
- return begin;
+ return view == mGentleHeader
+ || view == mPeopleHubView
+ || view == mAlertingHeader
+ || !Objects.equals(getBucket(view), getBucket(previous));
}
private boolean isUsingMultipleSections() {
return mNumberOfSections > 1;
}
- private @PriorityBucket int getBucket(ActivatableNotificationView view)
- throws IllegalArgumentException {
- if (view instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) view).getEntry().getBucket();
- } else if (view == mGentleHeader) {
+ @Nullable
+ private Integer getBucket(View view) {
+ if (view == mGentleHeader) {
return BUCKET_SILENT;
} else if (view == mPeopleHubView) {
return BUCKET_PEOPLE;
+ } else if (view == mAlertingHeader) {
+ return BUCKET_ALERTING;
+ } else if (view instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) view).getEntry().getBucket();
}
-
- throw new IllegalArgumentException("I don't know how to find a bucket for this view :(");
+ return null;
}
/**
@@ -251,118 +231,104 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
return;
}
- boolean peopleNotificationsPresent = false;
- int firstNonHeadsUpIndex = -1;
- int firstGentleIndex = -1;
- int notifCount = 0;
+ final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
+ final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();
- final int n = mParent.getChildCount();
- for (int i = 0; i < n; i++) {
- View child = mParent.getChildAt(i);
- if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
- notifCount++;
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) {
- firstNonHeadsUpIndex = i;
+ boolean peopleNotifsPresent = false;
+ int peopleHeaderTarget = -1;
+ int alertingHeaderTarget = -1;
+ int gentleHeaderTarget = -1;
+
+ int viewCount = 0;
+
+ if (showHeaders) {
+ final int childCount = mParent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = mParent.getChildAt(i);
+ if (child.getVisibility() == View.GONE
+ || !(child instanceof ExpandableNotificationRow)) {
+ continue;
}
- if (row.getEntry().getBucket() == BUCKET_PEOPLE) {
- peopleNotificationsPresent = true;
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ switch (row.getEntry().getBucket()) {
+ case BUCKET_PEOPLE:
+ if (peopleHeaderTarget == -1) {
+ peopleNotifsPresent = true;
+ peopleHeaderTarget = viewCount;
+ viewCount++;
+ }
+ break;
+ case BUCKET_ALERTING:
+ if (usingPeopleFiltering && alertingHeaderTarget == -1) {
+ alertingHeaderTarget = viewCount;
+ viewCount++;
+ }
+ break;
+ case BUCKET_SILENT:
+ if (gentleHeaderTarget == -1) {
+ gentleHeaderTarget = viewCount;
+ viewCount++;
+ }
+ break;
}
- if (row.getEntry().getBucket() == BUCKET_SILENT) {
- firstGentleIndex = i;
- break;
+ viewCount++;
+ }
+ if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
+ // Insert the people header even if there are no people visible, in order to show
+ // the hub. Put it directly above the next header.
+ if (alertingHeaderTarget != -1) {
+ peopleHeaderTarget = alertingHeaderTarget;
+ alertingHeaderTarget++;
+ gentleHeaderTarget++;
+ } else if (gentleHeaderTarget != -1) {
+ peopleHeaderTarget = gentleHeaderTarget;
+ gentleHeaderTarget++;
+ } else {
+ // Put it at the end of the list.
+ peopleHeaderTarget = viewCount;
}
}
}
- if (firstNonHeadsUpIndex == -1) {
- firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount;
- }
-
- // make room for peopleHub
- int offset = adjustPeopleHubVisibilityAndPosition(
- firstNonHeadsUpIndex, peopleNotificationsPresent);
- if (firstGentleIndex != -1) {
- firstGentleIndex += offset;
- }
-
- adjustGentleHeaderVisibilityAndPosition(firstGentleIndex);
+ // Allow swiping the people header if the section is empty
+ mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent);
- mGentleHeader.setAreThereDismissableGentleNotifs(
- mParent.hasActiveClearableNotifications(ROWS_GENTLE));
+ mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition(
+ peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible);
+ mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition(
+ alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible);
+ mGentleHeaderVisible = adjustHeaderVisibilityAndPosition(
+ gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible);
}
- private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) {
- final boolean showGentleHeader =
- firstGentleNotifIndex != -1
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
- final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader);
-
- if (!showGentleHeader) {
- if (mGentleHeaderVisible) {
- mGentleHeaderVisible = false;
- mParent.removeView(mGentleHeader);
+ private boolean adjustHeaderVisibilityAndPosition(
+ int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) {
+ if (targetIndex == -1) {
+ if (isCurrentlyVisible) {
+ mParent.removeView(header);
}
+ return false;
} else {
- if (!mGentleHeaderVisible) {
- mGentleHeaderVisible = true;
+ if (header instanceof SwipeableView) {
+ ((SwipeableView) header).resetTranslation();
+ }
+ if (!isCurrentlyVisible) {
// If the header is animating away, it will still have a parent, so detach it first
// TODO: We should really cancel the active animations here. This will happen
// automatically when the view's intro animation starts, but it's a fragile link.
- if (mGentleHeader.getTransientContainer() != null) {
- mGentleHeader.getTransientContainer().removeTransientView(mGentleHeader);
- mGentleHeader.setTransientContainer(null);
+ if (header.getTransientContainer() != null) {
+ header.getTransientContainer().removeTransientView(header);
+ header.setTransientContainer(null);
}
- mParent.addView(mGentleHeader, firstGentleNotifIndex);
- } else if (currentHeaderIndex != firstGentleNotifIndex - 1) {
- // Relocate the header to be immediately before the first child in the section
- int targetIndex = firstGentleNotifIndex;
- if (currentHeaderIndex < firstGentleNotifIndex) {
- // Adjust the target index to account for the header itself being temporarily
- // removed during the position change.
- targetIndex--;
- }
-
- mParent.changeViewPosition(mGentleHeader, targetIndex);
+ header.setContentVisible(true);
+ mParent.addView(header, targetIndex);
+ } else if (mParent.indexOfChild(header) != targetIndex) {
+ mParent.changeViewPosition(header, targetIndex);
}
+ return true;
}
}
- private int adjustPeopleHubVisibilityAndPosition(
- int targetIndex, boolean peopleNotificationsPresent) {
- final boolean showPeopleHeader = mNumberOfSections > 2
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
- && (peopleNotificationsPresent || mPeopleHubVisible);
- final int currentHubIndex = mParent.indexOfChild(mPeopleHubView);
- final boolean currentlyVisible = currentHubIndex >= 0;
-
- mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent);
-
- if (!showPeopleHeader) {
- if (currentlyVisible) {
- mParent.removeView(mPeopleHubView);
- return -1;
- }
- } else {
- mPeopleHubView.unDismiss();
- mPeopleHubView.resetTranslation();
- if (!currentlyVisible) {
- if (mPeopleHubView.getTransientContainer() != null) {
- mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView);
- mPeopleHubView.setTransientContainer(null);
- }
- mParent.addView(mPeopleHubView, targetIndex);
- return 1;
- } else if (currentHubIndex != targetIndex) {
- if (currentHubIndex < targetIndex) {
- targetIndex--;
- }
- mParent.changeViewPosition(mPeopleHubView, targetIndex);
- }
- }
- return 0;
- }
-
/**
* Updates the boundaries (as tracked by their first and last views) of the priority sections.
*
@@ -388,7 +354,12 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
//TODO: do this in a single pass, and more better
for (ActivatableNotificationView v : children) {
- if (getBucket(v) == filter) {
+ Integer bucket = getBucket(v);
+ if (bucket == null) {
+ throw new IllegalArgumentException("Cannot find section bucket for view");
+ }
+
+ if (bucket == filter) {
viewsInBucket.add(v);
}
@@ -463,16 +434,17 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
/**
* For now, declare the available notification buckets (sections) here so that other
* presentation code can decide what to do based on an entry's buckets
- *
*/
@Retention(SOURCE)
@IntDef(prefix = { "BUCKET_" }, value = {
+ BUCKET_HEADS_UP,
BUCKET_PEOPLE,
BUCKET_ALERTING,
BUCKET_SILENT
})
public @interface PriorityBucket {}
- public static final int BUCKET_PEOPLE = 0;
- public static final int BUCKET_ALERTING = 1;
- public static final int BUCKET_SILENT = 2;
+ public static final int BUCKET_HEADS_UP = 0;
+ public static final int BUCKET_PEOPLE = 1;
+ public static final int BUCKET_ALERTING = 2;
+ public static final int BUCKET_SILENT = 3;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2eeda1f48df3..1bd9bbecc26e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -815,7 +815,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
mShelf.onUiModeChanged();
- mSectionsManager.onUiModeChanged();
}
@ShadeViewRefactor(RefactorComponent.DECORATOR)
@@ -1632,8 +1631,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ExpandableView getChildAtPosition(float touchX, float touchY) {
- return getChildAtPosition(touchX, touchY, true /* requireMinHeight */);
-
+ return getChildAtPosition(
+ touchX, touchY, true /* requireMinHeight */, true /* ignoreDecors */);
}
/**
@@ -1642,17 +1641,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
* @param touchX the x coordinate
* @param touchY the y coordinate
* @param requireMinHeight Whether a minimum height is required for a child to be returned.
+ * @param ignoreDecors Whether decors can be returned
* @return the child at the given location.
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ExpandableView getChildAtPosition(float touchX, float touchY,
- boolean requireMinHeight) {
+ boolean requireMinHeight, boolean ignoreDecors) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
for (int childIdx = 0; childIdx < count; childIdx++) {
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
if (slidingChild.getVisibility() != VISIBLE
- || slidingChild instanceof StackScrollerDecorView) {
+ || (ignoreDecors && slidingChild instanceof StackScrollerDecorView)) {
continue;
}
float childTop = slidingChild.getTranslationY();
@@ -4166,7 +4166,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
mScrolledToTopOnFirstDown = isScrolledToTop();
- if (getChildAtPosition(ev.getX(), y, false /* requireMinHeight */) == null) {
+ final ExpandableView childAtTouchPos = getChildAtPosition(
+ ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */);
+ if (childAtTouchPos == null) {
setIsBeingDragged(false);
recycleVelocityTracker();
break;
@@ -6299,8 +6301,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
if (view instanceof PeopleHubView) {
- PeopleHubView row = (PeopleHubView) view;
- row.dismiss(false);
mSectionsManager.hidePeopleRow();
}
@@ -6325,8 +6325,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public View getChildAtPosition(MotionEvent ev) {
- View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
- ev.getY());
+ View child = NotificationStackScrollLayout.this.getChildAtPosition(
+ ev.getX(),
+ ev.getY(),
+ true /* requireMinHeight */,
+ false /* ignoreDecors */);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
ExpandableNotificationRow parent = row.getNotificationParent();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index e5717aeefdcb..151c6b272a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -25,30 +25,32 @@ import com.android.systemui.R
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
import com.android.systemui.statusbar.notification.people.DataListener
import com.android.systemui.statusbar.notification.people.PersonViewModel
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
class PeopleHubView(context: Context, attrs: AttributeSet) :
- ActivatableNotificationView(context, attrs), SwipeableView {
+ StackScrollerDecorView(context, attrs), SwipeableView {
private lateinit var contents: ViewGroup
- private lateinit var personControllers: List<PersonDataListenerImpl>
- val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
- get() = personControllers.asSequence()
+ lateinit var personViewAdapters: Sequence<DataListener<PersonViewModel?>>
+ private set
override fun onFinishInflate() {
- super.onFinishInflate()
contents = requireViewById(R.id.people_list)
- personControllers = (0 until contents.childCount)
+ personViewAdapters = (0 until contents.childCount)
.reversed()
.asSequence()
.mapNotNull { idx ->
(contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
}
.toList()
+ .asSequence()
+ super.onFinishInflate()
+ setVisible(true /* nowVisible */, false /* animate */)
}
- override fun getContentView(): View = contents
+ override fun findContentView(): View = contents
+ override fun findSecondaryView(): View? = null
override fun hasFinishedInitialization(): Boolean = true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index add982dabf02..ad3ff69eb5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.notification.stack;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.content.Context;
-import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -28,7 +28,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import java.util.Objects;
@@ -36,23 +36,22 @@ import java.util.Objects;
* Similar in size and appearance to the NotificationShelf, appears at the beginning of some
* notification sections. Currently only used for gentle notifications.
*/
-public class SectionHeaderView extends ActivatableNotificationView {
+public class SectionHeaderView extends StackScrollerDecorView {
private ViewGroup mContents;
private TextView mLabelView;
private ImageView mClearAllButton;
@Nullable private View.OnClickListener mOnClearClickListener = null;
- private final RectF mTmpRect = new RectF();
-
public SectionHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
- super.onFinishInflate();
mContents = Objects.requireNonNull(findViewById(R.id.content));
bindContents();
+ super.onFinishInflate();
+ setVisible(true /* nowVisible */, false /* animate */);
}
private void bindContents() {
@@ -64,15 +63,20 @@ public class SectionHeaderView extends ActivatableNotificationView {
}
@Override
- protected View getContentView() {
+ protected View findContentView() {
return mContents;
}
+ @Override
+ protected View findSecondaryView() {
+ return null;
+ }
+
/**
* Destroys and reinflates the visible contents of the section header. For use on configuration
* changes or any other time that layout values might need to be re-evaluated.
*
- * Does not reinflate the base content view itself ({@link #getContentView()} or any of the
+ * Does not reinflate the base content view itself ({@link #findContentView()} or any of the
* decorator views, such as the background view or shadow view.
*/
void reinflateContents() {
@@ -88,35 +92,20 @@ public class SectionHeaderView extends ActivatableNotificationView {
return true;
}
- /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
- void onUiModeChanged() {
- updateBackgroundColors();
- mLabelView.setTextColor(
- getContext().getColor(R.color.notification_section_header_label_color));
- mClearAllButton.setImageResource(
- R.drawable.status_bar_notification_section_header_clear_btn);
- }
-
void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) {
mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE);
}
@Override
- protected boolean disallowSingleClick(MotionEvent event) {
- // Disallow single click on lockscreen if user is tapping on clear all button
- mTmpRect.set(
- mClearAllButton.getLeft(),
- mClearAllButton.getTop(),
- mClearAllButton.getLeft() + mClearAllButton.getWidth(),
- mClearAllButton.getTop() + mClearAllButton.getHeight());
- return mTmpRect.contains(event.getX(), event.getY());
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return super.onInterceptTouchEvent(ev);
}
/**
* Fired whenever the user clicks on the body of the header (e.g. no sub-buttons or anything).
*/
void setOnHeaderClickListener(View.OnClickListener listener) {
- mContents.setOnClickListener(listener);
+ mLabelView.setOnClickListener(listener);
}
/** Fired when the user clicks on the "X" button on the far right of the header. */
@@ -124,4 +113,8 @@ public class SectionHeaderView extends ActivatableNotificationView {
mOnClearClickListener = listener;
mClearAllButton.setOnClickListener(listener);
}
+
+ void setHeaderText(@StringRes int resId) {
+ mLabelView.setText(resId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 691e1c422bfe..1dde5c03a627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -150,14 +150,26 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private KeyguardViewMediator mKeyguardViewMediator;
private ScrimController mScrimController;
private StatusBar mStatusBar;
- private int mPendingAuthenticatedUserId = -1;
- private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
+ private PendingAuthenticated mPendingAuthenticated = null;
private boolean mPendingShowBouncer;
private boolean mHasScreenTurnedOnSinceAuthenticating;
private boolean mFadedAwayAfterWakeAndUnlock;
private final MetricsLogger mMetricsLogger;
+ private static final class PendingAuthenticated {
+ public final int userId;
+ public final BiometricSourceType biometricSourceType;
+ public final boolean isStrongBiometric;
+
+ PendingAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ this.userId = userId;
+ this.biometricSourceType = biometricSourceType;
+ this.isStrongBiometric = isStrongBiometric;
+ }
+ }
+
@Inject
public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
@@ -251,28 +263,30 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
}
@Override
- public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
- mPendingAuthenticatedUserId = userId;
- mPendingAuthenticatedBioSourceType = biometricSourceType;
+ mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType,
+ isStrongBiometric);
Trace.endSection();
return;
}
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
.setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
- biometricSourceType);
+ biometricSourceType, isStrongBiometric);
if (unlockAllowed) {
mKeyguardViewMediator.userActivity();
- startWakeAndUnlock(biometricSourceType);
+ startWakeAndUnlock(biometricSourceType, isStrongBiometric);
} else {
Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
}
}
- public void startWakeAndUnlock(BiometricSourceType biometricSourceType) {
- startWakeAndUnlock(calculateMode(biometricSourceType));
+ public void startWakeAndUnlock(BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ startWakeAndUnlock(calculateMode(biometricSourceType, isStrongBiometric));
}
public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
@@ -373,45 +387,46 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
public void onStartedGoingToSleep(int why) {
resetMode();
mFadedAwayAfterWakeAndUnlock = false;
- mPendingAuthenticatedUserId = -1;
- mPendingAuthenticatedBioSourceType = null;
+ mPendingAuthenticated = null;
}
@Override
public void onFinishedGoingToSleep(int why) {
Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
- BiometricSourceType pendingType = mPendingAuthenticatedBioSourceType;
- int pendingUserId = mPendingAuthenticatedUserId;
- if (pendingUserId != -1 && pendingType != null) {
+ if (mPendingAuthenticated != null) {
// Post this to make sure it's executed after the device is fully locked.
- mHandler.post(() -> onBiometricAuthenticated(pendingUserId, pendingType));
+ mHandler.post(() -> onBiometricAuthenticated(mPendingAuthenticated.userId,
+ mPendingAuthenticated.biometricSourceType,
+ mPendingAuthenticated.isStrongBiometric));
+ mPendingAuthenticated = null;
}
- mPendingAuthenticatedUserId = -1;
- mPendingAuthenticatedBioSourceType = null;
Trace.endSection();
}
public boolean hasPendingAuthentication() {
- return mPendingAuthenticatedUserId != -1
- && mUpdateMonitor.isUnlockingWithBiometricAllowed()
- && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
+ return mPendingAuthenticated != null
+ && mUpdateMonitor
+ .isUnlockingWithBiometricAllowed(mPendingAuthenticated.isStrongBiometric)
+ && mPendingAuthenticated.userId == KeyguardUpdateMonitor.getCurrentUser();
}
public int getMode() {
return mMode;
}
- private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType) {
+ private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
if (biometricSourceType == BiometricSourceType.FACE
|| biometricSourceType == BiometricSourceType.IRIS) {
- return calculateModeForPassiveAuth();
+ return calculateModeForPassiveAuth(isStrongBiometric);
} else {
- return calculateModeForFingerprint();
+ return calculateModeForFingerprint(isStrongBiometric);
}
}
- private @WakeAndUnlockMode int calculateModeForFingerprint() {
- boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+ private @WakeAndUnlockMode int calculateModeForFingerprint(boolean isStrongBiometric) {
+ boolean unlockingAllowed =
+ mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
boolean deviceDreaming = mUpdateMonitor.isDreaming();
if (!mUpdateMonitor.isDeviceInteractive()) {
@@ -440,8 +455,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
return MODE_NONE;
}
- private @WakeAndUnlockMode int calculateModeForPassiveAuth() {
- boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+ private @WakeAndUnlockMode int calculateModeForPassiveAuth(boolean isStrongBiometric) {
+ boolean unlockingAllowed =
+ mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
boolean deviceDreaming = mUpdateMonitor.isDreaming();
boolean bypass = mKeyguardBypassController.getBypassEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index b4d0d479ff39..03918e09be5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -38,11 +38,20 @@ open class KeyguardBypassController : Dumpable {
private val mKeyguardStateController: KeyguardStateController
private val statusBarStateController: StatusBarStateController
private var hasFaceFeature: Boolean
+ private var pendingUnlock: PendingUnlock? = null
/**
+ * Pending unlock info:
+ *
* The pending unlock type which is set if the bypass was blocked when it happened.
+ *
+ * Whether the pending unlock type is strong biometric or non-strong biometric
+ * (i.e. weak or convenience).
*/
- private var pendingUnlockType: BiometricSourceType? = null
+ private data class PendingUnlock(
+ val pendingUnlockType: BiometricSourceType,
+ val isStrongBiometric: Boolean
+ )
lateinit var unlockController: BiometricUnlockController
var isPulseExpanding = false
@@ -86,7 +95,7 @@ open class KeyguardBypassController : Dumpable {
statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
override fun onStateChanged(newState: Int) {
if (newState != StatusBarState.KEYGUARD) {
- pendingUnlockType = null
+ pendingUnlock = null
}
}
})
@@ -101,7 +110,7 @@ open class KeyguardBypassController : Dumpable {
lockscreenUserManager.addUserChangedListener(
object : NotificationLockscreenUserManager.UserChangedListener {
override fun onUserChanged(userId: Int) {
- pendingUnlockType = null
+ pendingUnlock = null
}
})
}
@@ -111,11 +120,14 @@ open class KeyguardBypassController : Dumpable {
*
* @return false if we can not wake and unlock right now
*/
- fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
+ fun onBiometricAuthenticated(
+ biometricSourceType: BiometricSourceType,
+ isStrongBiometric: Boolean
+ ): Boolean {
if (bypassEnabled) {
val can = canBypass()
if (!can && (isPulseExpanding || qSExpanded)) {
- pendingUnlockType = biometricSourceType
+ pendingUnlock = PendingUnlock(biometricSourceType, isStrongBiometric)
}
return can
}
@@ -123,10 +135,12 @@ open class KeyguardBypassController : Dumpable {
}
fun maybePerformPendingUnlock() {
- if (pendingUnlockType != null) {
- if (onBiometricAuthenticated(pendingUnlockType!!)) {
- unlockController.startWakeAndUnlock(pendingUnlockType)
- pendingUnlockType = null
+ if (pendingUnlock != null) {
+ if (onBiometricAuthenticated(pendingUnlock!!.pendingUnlockType,
+ pendingUnlock!!.isStrongBiometric)) {
+ unlockController.startWakeAndUnlock(pendingUnlock!!.pendingUnlockType,
+ pendingUnlock!!.isStrongBiometric)
+ pendingUnlock = null
}
}
}
@@ -162,12 +176,17 @@ open class KeyguardBypassController : Dumpable {
}
fun onStartedGoingToSleep() {
- pendingUnlockType = null
+ pendingUnlock = null
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("KeyguardBypassController:")
- pw.println(" pendingUnlockType: $pendingUnlockType")
+ if (pendingUnlock != null) {
+ pw.println(" mPendingUnlock.pendingUnlockType: ${pendingUnlock!!.pendingUnlockType}")
+ pw.println(" mPendingUnlock.isStrongBiometric: ${pendingUnlock!!.isStrongBiometric}")
+ } else {
+ pw.println(" mPendingUnlock: $pendingUnlock")
+ }
pw.println(" bypassEnabled: $bypassEnabled")
pw.println(" canBypass: ${canBypass()}")
pw.println(" bouncerShowing: $bouncerShowing")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 60589843002e..61cef6827bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -387,7 +387,12 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
- boolean unlockingAllowed = mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed();
+ // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
+ // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
+ // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
+ // check of whether non-strong biometric is allowed
+ boolean unlockingAllowed = mKeyguardUpdateMonitor
+ .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
if (fingerprintRunning && unlockingAllowed) {
AccessibilityNodeInfo.AccessibilityAction unlock
= new AccessibilityNodeInfo.AccessibilityAction(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index fb7976ff19a8..c61d7bbf67c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -202,8 +202,10 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType) {
- if (mFirstBypassAttempt && mUpdateMonitor.isUnlockingWithBiometricAllowed()) {
+ BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ if (mFirstBypassAttempt
+ && mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
mDelayShowingKeyguardStatusBar = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 10821d63d4cc..945a9db7c836 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.app.AlarmManager;
-import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -45,7 +44,6 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -116,7 +114,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
*/
- public static final float BUSY_SCRIM_ALPHA = 0.54f;
+ public static final float BUSY_SCRIM_ALPHA = 0.75f;
/**
* The most common scrim, the one under the keyguard.
@@ -146,8 +144,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
- private float mScrimBehindAlpha;
- private float mScrimBehindAlphaResValue;
private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
// Assuming the shade is expanded during initialization
@@ -192,7 +188,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
@Inject
public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
- @Main Resources resources,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
DockManager dockManager) {
@@ -203,14 +198,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
- mScrimBehindAlphaResValue = resources.getFloat(R.dimen.scrim_behind_alpha);
mHandler = handler;
mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
"hide_aod_wallpaper", mHandler);
mWakeLock = delayedWakeLockBuilder.setHandler(mHandler).setTag("Scrims").build();
// Scrim alpha is initially set to the value on the resource but might be changed
// to make sure that text on top of it is legible.
- mScrimBehindAlpha = mScrimBehindAlphaResValue;
mDozeParameters = dozeParameters;
mDockManager = dockManager;
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -587,7 +580,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
int mainColor = mColors.getMainColor();
float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
4.5f /* minimumContrast */) / 255f;
- mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
dispatchScrimState(mScrimBehind.getViewAlpha());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index ba55f2ddcf13..c404cf69f1a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -74,6 +74,12 @@ public class UserAvatarView extends View {
this(context, null);
}
+ @Override
+ public void setActivated(boolean activated) {
+ super.setActivated(activated);
+ mDrawable.invalidateSelf();
+ }
+
/**
* @deprecated use {@link #setAvatar(Bitmap)} instead.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 0ab08a8fd168..a7f60d64c332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -293,13 +293,12 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
}
@Override
- public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
+ public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
Trace.beginSection("KeyguardUpdateMonitorCallback#onBiometricAuthenticated");
- if (!mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()) {
- Trace.endSection();
- return;
+ if (mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
+ update(false /* updateAlways */);
}
- update(false /* updateAlways */);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index d28a66994e1d..2abae3e26013 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -257,6 +257,7 @@ public class KeyguardUserSwitcher {
private Context mContext;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
+ private View mCurrentUserView;
public Adapter(Context context, UserSwitcherController controller,
KeyguardUserSwitcher kgu) {
@@ -285,6 +286,9 @@ public class KeyguardUserSwitcher {
// Disable the icon if switching is disabled
v.setAvatarEnabled(item.isSwitchToEnabled);
convertView.setActivated(item.isCurrent);
+ if (item.isCurrent) {
+ mCurrentUserView = convertView;
+ }
convertView.setTag(item);
return convertView;
}
@@ -297,6 +301,12 @@ public class KeyguardUserSwitcher {
// tapping the guest user while it's current clears the session.
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
} else if (user.isSwitchToEnabled) {
+ if (!user.isAddUser && !user.isRestricted && !user.isDisabledByAdmin) {
+ if (mCurrentUserView != null) {
+ mCurrentUserView.setActivated(false);
+ }
+ v.setActivated(true);
+ }
switchTo(user);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 8dfcb0ac215d..9ce31d030c43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -236,8 +236,7 @@ public class UserSwitcherController implements Dumpable {
picture, avatarSize, avatarSize, true);
}
}
- int index = isCurrent ? 0 : records.size();
- records.add(index, new UserRecord(info, picture, false /* isGuest */,
+ records.add(new UserRecord(info, picture, false /* isGuest */,
isCurrent, false /* isAddUser */, false /* isRestricted */,
switchToEnabled));
}
@@ -269,8 +268,7 @@ public class UserSwitcherController implements Dumpable {
records.add(guestRecord);
}
} else {
- int index = guestRecord.isCurrent ? 0 : records.size();
- records.add(index, guestRecord);
+ records.add(guestRecord);
}
if (canCreateUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index f4157f21e158..8625d63a3c7e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -126,6 +126,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
internal var startAction: () -> Unit = ::startInternal
/**
+ * Action to run when [cancel] is called. This can be changed by
+ * [PhysicsAnimatorTestUtils.prepareForTest] to cancel animations from the main thread, which
+ * is required.
+ */
+ internal var cancelAction: (Set<FloatPropertyCompat<in T>>) -> Unit = ::cancelInternal
+
+ /**
* Springs a property to the given value, using the provided configuration settings.
*
* Springs are used when you know the exact value to which you want to animate. They can be
@@ -429,10 +436,13 @@ class PhysicsAnimator<T> private constructor (val target: T) {
max = max(currentValue, this.max)
}
- // Apply the configuration and start the animation. Since flings can't be
- // redirected while in motion, cancel it first.
+ // Flings can't be updated to a new position while maintaining velocity, because
+ // we're using the explicitly provided start velocity. Cancel any flings (or
+ // springs) on this property before flinging.
+ cancel(animatedProperty)
+
+ // Apply the configuration and start the animation.
getFlingAnimation(animatedProperty)
- .also { it.cancel() }
.also { flingConfig.applyToAnimation(it) }
.start()
}
@@ -707,11 +717,26 @@ class PhysicsAnimator<T> private constructor (val target: T) {
return springConfigs.keys.union(flingConfigs.keys)
}
+ /**
+ * Cancels the given properties. This is typically called immediately by [cancel], unless this
+ * animator is under test.
+ */
+ internal fun cancelInternal(properties: Set<FloatPropertyCompat<in T>>) {
+ for (property in properties) {
+ flingAnimations[property]?.cancel()
+ springAnimations[property]?.cancel()
+ }
+ }
+
/** Cancels all in progress animations on all properties. */
fun cancel() {
- for (dynamicAnim in flingAnimations.values.union(springAnimations.values)) {
- dynamicAnim.cancel()
- }
+ cancelAction(flingAnimations.keys)
+ cancelAction(springAnimations.keys)
+ }
+
+ /** Cancels in progress animations on the provided properties only. */
+ fun cancel(vararg properties: FloatPropertyCompat<in T>) {
+ cancelAction(properties.toSet())
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
index 965decd255a0..c50eeac80d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimatorTestUtils.kt
@@ -363,8 +363,12 @@ object PhysicsAnimatorTestUtils {
private val testEndListeners = ArrayList<PhysicsAnimator.EndListener<T>>()
private val testUpdateListeners = ArrayList<PhysicsAnimator.UpdateListener<T>>()
+ /** Whether we're currently in the middle of executing startInternal(). */
+ private var currentlyRunningStartInternal = false
+
init {
animator.startAction = ::startForTest
+ animator.cancelAction = ::cancelForTest
}
internal fun addTestEndListener(listener: PhysicsAnimator.EndListener<T>) {
@@ -437,7 +441,29 @@ object PhysicsAnimatorTestUtils {
}
})
+ currentlyRunningStartInternal = true
animator.startInternal()
+ currentlyRunningStartInternal = false
+ unblockLatch.countDown()
+ }
+
+ unblockLatch.await(timeoutMs, TimeUnit.MILLISECONDS)
+ }
+
+ private fun cancelForTest(properties: Set<FloatPropertyCompat<in T>>) {
+ // If this was called from startInternal, we are already on the animation thread, and
+ // should just call cancelInternal rather than posting it. If we post it, the
+ // cancellation will occur after the rest of startInternal() and we'll immediately
+ // cancel the animation we worked so hard to start!
+ if (currentlyRunningStartInternal) {
+ animator.cancelInternal(properties)
+ return
+ }
+
+ val unblockLatch = CountDownLatch(1)
+
+ animationThreadHandler.post {
+ animator.cancelInternal(properties)
unblockLatch.countDown()
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
new file mode 100644
index 000000000000..2276ba19e432
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.magnetictarget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.PointF
+import android.os.Handler
+import android.os.UserHandle
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.provider.Settings
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.View
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.systemui.util.animation.PhysicsAnimator
+import kotlin.math.hypot
+
+/**
+ * Utility class for creating 'magnetized' objects that are attracted to one or more magnetic
+ * targets. Magnetic targets attract objects that are dragged near them, and hold them there unless
+ * they're moved away or released. Releasing objects inside a magnetic target typically performs an
+ * action on the object.
+ *
+ * MagnetizedObject also supports flinging to targets, which will result in the object being pulled
+ * into the target and released as if it was dragged into it.
+ *
+ * To use this class, either construct an instance with an object of arbitrary type, or use the
+ * [MagnetizedObject.magnetizeView] shortcut method if you're magnetizing a view. Then, set
+ * [magnetListener] to receive event callbacks. In your touch handler, pass all MotionEvents
+ * that move this object to [maybeConsumeMotionEvent]. If that method returns true, consider the
+ * event consumed by the MagnetizedObject and don't move the object unless it begins returning false
+ * again.
+ *
+ * @param context Context, used to retrieve a Vibrator instance for vibration effects.
+ * @param underlyingObject The actual object that we're magnetizing.
+ * @param xProperty Property that sets the x value of the object's position.
+ * @param yProperty Property that sets the y value of the object's position.
+ */
+abstract class MagnetizedObject<T : Any>(
+ val context: Context,
+
+ /** The actual object that is animated. */
+ val underlyingObject: T,
+
+ /** Property that gets/sets the object's X value. */
+ val xProperty: FloatPropertyCompat<in T>,
+
+ /** Property that gets/sets the object's Y value. */
+ val yProperty: FloatPropertyCompat<in T>
+) {
+
+ /** Return the width of the object. */
+ abstract fun getWidth(underlyingObject: T): Float
+
+ /** Return the height of the object. */
+ abstract fun getHeight(underlyingObject: T): Float
+
+ /**
+ * Fill the provided array with the location of the top-left of the object, relative to the
+ * entire screen. Compare to [View.getLocationOnScreen].
+ */
+ abstract fun getLocationOnScreen(underlyingObject: T, loc: IntArray)
+
+ /** Methods for listening to events involving a magnetized object. */
+ interface MagnetListener {
+
+ /**
+ * Called when touch events move within the magnetic field of a target, causing the
+ * object to animate to the target and become 'stuck' there. The animation happens
+ * automatically here - you should not move the object. You can, however, change its state
+ * to indicate to the user that it's inside the target and releasing it will have an effect.
+ *
+ * [maybeConsumeMotionEvent] is now returning true and will continue to do so until a call
+ * to [onUnstuckFromTarget] or [onReleasedInTarget].
+ *
+ * @param target The target that the object is now stuck to.
+ */
+ fun onStuckToTarget(target: MagneticTarget)
+
+ /**
+ * Called when the object is no longer stuck to a target. This means that either touch
+ * events moved outside of the magnetic field radius, or that a forceful fling out of the
+ * target was detected.
+ *
+ * The object won't be automatically animated out of the target, since you're responsible
+ * for moving the object again. You should move it (or animate it) using your own
+ * movement/animation logic.
+ *
+ * Reverse any effects applied in [onStuckToTarget] here.
+ *
+ * If [wasFlungOut] is true, [maybeConsumeMotionEvent] returned true for the ACTION_UP event
+ * that concluded the fling. If [wasFlungOut] is false, that means a drag gesture is ongoing
+ * and [maybeConsumeMotionEvent] is now returning false.
+ *
+ * @param target The target that this object was just unstuck from.
+ * @param velX The X velocity of the touch gesture when it exited the magnetic field.
+ * @param velY The Y velocity of the touch gesture when it exited the magnetic field.
+ * @param wasFlungOut Whether the object was unstuck via a fling gesture. This means that
+ * an ACTION_UP event was received, and that the gesture velocity was sufficient to conclude
+ * that the user wants to un-stick the object despite no touch events occurring outside of
+ * the magnetic field radius.
+ */
+ fun onUnstuckFromTarget(
+ target: MagneticTarget,
+ velX: Float,
+ velY: Float,
+ wasFlungOut: Boolean
+ )
+
+ /**
+ * Called when the object is released inside a target, or flung towards it with enough
+ * velocity to reach it.
+ *
+ * @param target The target that the object was released in.
+ */
+ fun onReleasedInTarget(target: MagneticTarget)
+ }
+
+ private val animator: PhysicsAnimator<T> = PhysicsAnimator.getInstance(underlyingObject)
+ private val objectLocationOnScreen = IntArray(2)
+
+ /**
+ * Targets that have been added to this object. These will all be considered when determining
+ * magnetic fields and fling trajectories.
+ */
+ private val associatedTargets = ArrayList<MagneticTarget>()
+
+ private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
+ private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
+
+ /** Whether touch events are presently occurring within the magnetic field area of a target. */
+ val objectStuckToTarget: Boolean
+ get() = targetObjectIsStuckTo != null
+
+ /** The target the object is stuck to, or null if the object is not stuck to any target. */
+ private var targetObjectIsStuckTo: MagneticTarget? = null
+
+ /**
+ * Sets the listener to receive events. This must be set, or [maybeConsumeMotionEvent]
+ * will always return false and no magnetic effects will occur.
+ */
+ lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+ /**
+ * Sets whether forcefully flinging the object vertically towards a target causes it to be
+ * attracted to the target and then released immediately, despite never being dragged within the
+ * magnetic field.
+ */
+ var flingToTargetEnabled = true
+
+ /**
+ * If fling to target is enabled, forcefully flinging the object towards a target will cause
+ * it to be attracted to the target and then released immediately, despite never being dragged
+ * within the magnetic field.
+ *
+ * This sets the width of the area considered 'near' enough a target to be considered a fling,
+ * in terms of percent of the target view's width. For example, setting this to 3f means that
+ * flings towards a 100px-wide target will be considered 'near' enough if they're towards the
+ * 300px-wide area around the target.
+ *
+ * Flings whose trajectory intersects the area will be attracted and released - even if the
+ * target view itself isn't intersected:
+ *
+ * | |
+ * | 0 |
+ * | / |
+ * | / |
+ * | X / |
+ * |.....###.....|
+ *
+ *
+ * Flings towards the target whose trajectories do not intersect the area will be treated as
+ * normal flings and the magnet will leave the object alone:
+ *
+ * | |
+ * | |
+ * | 0 |
+ * | / |
+ * | / X |
+ * |.....###.....|
+ *
+ */
+ var flingToTargetWidthPercent = 3f
+
+ /**
+ * Sets the minimum velocity (in pixels per second) required to fling an object to the target
+ * without dragging it into the magnetic field.
+ */
+ var flingToTargetMinVelocity = 4000f
+
+ /**
+ * Sets the minimum velocity (in pixels per second) required to fling un-stuck an object stuck
+ * to the target. If this velocity is reached, the object will be freed even if it wasn't moved
+ * outside the magnetic field radius.
+ */
+ var flingUnstuckFromTargetMinVelocity = 1000f
+
+ /**
+ * Sets the maximum velocity above which the object will not stick to the target. Even if the
+ * object is dragged through the magnetic field, it will not stick to the target until the
+ * velocity is below this value.
+ */
+ var stickToTargetMaxVelocity = 2000f
+
+ /**
+ * Enable or disable haptic vibration effects when the object interacts with the magnetic field.
+ *
+ * If you're experiencing crashes when the object enters targets, ensure that you have the
+ * android.permission.VIBRATE permission!
+ */
+ var hapticsEnabled = true
+
+ /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */
+ private var systemHapticsEnabled = false
+
+ /** Default spring configuration to use for animating the object into a target. */
+ var springConfig = PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY)
+
+ /**
+ * Spring configuration to use to spring the object into a target specifically when it's flung
+ * towards (rather than dragged near) it.
+ */
+ var flungIntoTargetSpringConfig = springConfig
+
+ init {
+ val hapticSettingObserver =
+ object : ContentObserver(Handler.getMain()) {
+ override fun onChange(selfChange: Boolean) {
+ systemHapticsEnabled =
+ Settings.System.getIntForUser(
+ context.contentResolver,
+ Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ 0,
+ UserHandle.USER_CURRENT) != 0
+ }
+ }
+
+ context.contentResolver.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
+ true /* notifyForDescendants */, hapticSettingObserver)
+
+ // Trigger the observer once to initialize systemHapticsEnabled.
+ hapticSettingObserver.onChange(false /* selfChange */)
+ }
+
+ /**
+ * Adds the provided MagneticTarget to this object. The object will now be attracted to the
+ * target if it strays within its magnetic field or is flung towards it.
+ *
+ * If this target (or its magnetic field) overlaps another target added to this object, the
+ * prior target will take priority.
+ */
+ fun addTarget(target: MagneticTarget) {
+ associatedTargets.add(target)
+ target.updateLocationOnScreen()
+ }
+
+ /**
+ * Shortcut that accepts a View and a magnetic field radius and adds it as a magnetic target.
+ *
+ * @return The MagneticTarget instance for the given View. This can be used to change the
+ * target's magnetic field radius after it's been added. It can also be added to other
+ * magnetized objects.
+ */
+ fun addTarget(target: View, magneticFieldRadiusPx: Int): MagneticTarget {
+ return MagneticTarget(target, magneticFieldRadiusPx).also { addTarget(it) }
+ }
+
+ /**
+ * Removes the given target from this object. The target will no longer attract the object.
+ */
+ fun removeTarget(target: MagneticTarget) {
+ associatedTargets.remove(target)
+ }
+
+ /**
+ * Provide this method with all motion events that move the magnetized object. If the
+ * location of the motion events moves within the magnetic field of a target, or indicate a
+ * fling-to-target gesture, this method will return true and you should not move the object
+ * yourself until it returns false again.
+ *
+ * Note that even when this method returns true, you should continue to pass along new motion
+ * events so that we know when the events move back outside the magnetic field area.
+ *
+ * This method will always return false if you haven't set a [magnetListener].
+ */
+ fun maybeConsumeMotionEvent(ev: MotionEvent): Boolean {
+ // Short-circuit if we don't have a listener or any targets, since those are required.
+ if (associatedTargets.size == 0) {
+ return false
+ }
+
+ // When a gesture begins, recalculate target views' positions on the screen in case they
+ // have changed. Also, clear state.
+ if (ev.action == MotionEvent.ACTION_DOWN) {
+ updateTargetViewLocations()
+
+ // Clear the velocity tracker and assume we're not stuck to a target yet.
+ velocityTracker.clear()
+ targetObjectIsStuckTo = null
+ }
+
+ addMovement(ev)
+
+ val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
+ val distanceFromTargetCenter = hypot(
+ ev.rawX - target.centerOnScreen.x,
+ ev.rawY - target.centerOnScreen.y)
+ distanceFromTargetCenter < target.magneticFieldRadiusPx
+ }
+
+ // If we aren't currently stuck to a target, and we're in the magnetic field of a target,
+ // we're newly stuck.
+ val objectNewlyStuckToTarget =
+ !objectStuckToTarget && targetObjectIsInMagneticFieldOf != null
+
+ // If we are currently stuck to a target, we're in the magnetic field of a target, and that
+ // target isn't the one we're currently stuck to, then touch events have moved into a
+ // adjacent target's magnetic field.
+ val objectMovedIntoDifferentTarget =
+ objectStuckToTarget &&
+ targetObjectIsInMagneticFieldOf != null &&
+ targetObjectIsStuckTo != targetObjectIsInMagneticFieldOf
+
+ if (objectNewlyStuckToTarget || objectMovedIntoDifferentTarget) {
+ velocityTracker.computeCurrentVelocity(1000)
+ val velX = velocityTracker.xVelocity
+ val velY = velocityTracker.yVelocity
+
+ // If the object is moving too quickly within the magnetic field, do not stick it. This
+ // only applies to objects newly stuck to a target. If the object is moved into a new
+ // target, it wasn't moving at all (since it was stuck to the previous one).
+ if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) {
+ return false
+ }
+
+ // This touch event is newly within the magnetic field - let the listener know, and
+ // animate sticking to the magnet.
+ targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
+ cancelAnimations()
+ magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
+ animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ } else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
+ velocityTracker.computeCurrentVelocity(1000)
+
+ // This touch event is newly outside the magnetic field - let the listener know. It will
+ // move the object out of the target using its own movement logic.
+ cancelAnimations()
+ magnetListener.onUnstuckFromTarget(
+ targetObjectIsStuckTo!!, velocityTracker.xVelocity, velocityTracker.yVelocity,
+ wasFlungOut = false)
+ targetObjectIsStuckTo = null
+
+ vibrateIfEnabled(VibrationEffect.EFFECT_TICK)
+ }
+
+ // First, check for relevant gestures concluding with an ACTION_UP.
+ if (ev.action == MotionEvent.ACTION_UP) {
+
+ velocityTracker.computeCurrentVelocity(1000 /* units */)
+ val velX = velocityTracker.xVelocity
+ val velY = velocityTracker.yVelocity
+
+ // Cancel the magnetic animation since we might still be springing into the magnetic
+ // target, but we're about to fling away or release.
+ cancelAnimations()
+
+ if (objectStuckToTarget) {
+ if (hypot(velX, velY) > flingUnstuckFromTargetMinVelocity) {
+ // If the object is stuck, but it was forcefully flung away from the target,
+ // tell the listener so the object can be animated out of the target.
+ magnetListener.onUnstuckFromTarget(
+ targetObjectIsStuckTo!!, velX, velY, wasFlungOut = true)
+ } else {
+ // If the object is stuck and not flung away, it was released inside the target.
+ magnetListener.onReleasedInTarget(targetObjectIsStuckTo!!)
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ }
+
+ // Either way, we're no longer stuck.
+ targetObjectIsStuckTo = null
+ return true
+ }
+
+ // The target we're flinging towards, or null if we're not flinging towards any target.
+ val flungToTarget = associatedTargets.firstOrNull { target ->
+ isForcefulFlingTowardsTarget(target, ev.rawX, ev.rawY, velX, velY)
+ }
+
+ if (flungToTarget != null) {
+ // If this is a fling-to-target, animate the object to the magnet and then release
+ // it.
+ magnetListener.onStuckToTarget(flungToTarget)
+ targetObjectIsStuckTo = flungToTarget
+
+ animateStuckToTarget(flungToTarget, velX, velY, true) {
+ targetObjectIsStuckTo = null
+ magnetListener.onReleasedInTarget(flungToTarget)
+ vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
+ }
+
+ return true
+ }
+
+ // If it's not either of those things, we are not interested.
+ return false
+ }
+
+ return objectStuckToTarget // Always consume touch events if the object is stuck.
+ }
+
+ /** Plays the given vibration effect if haptics are enabled. */
+ @SuppressLint("MissingPermission")
+ private fun vibrateIfEnabled(effect: Int) {
+ if (hapticsEnabled && systemHapticsEnabled) {
+ vibrator.vibrate(effect.toLong())
+ }
+ }
+
+ /** Adds the movement to the velocity tracker using raw coordinates. */
+ private fun addMovement(event: MotionEvent) {
+ // Add movement to velocity tracker using raw screen X and Y coordinates instead
+ // of window coordinates because the window frame may be moving at the same time.
+ val deltaX = event.rawX - event.x
+ val deltaY = event.rawY - event.y
+ event.offsetLocation(deltaX, deltaY)
+ velocityTracker.addMovement(event)
+ event.offsetLocation(-deltaX, -deltaY)
+ }
+
+ /** Animates sticking the object to the provided target with the given start velocities. */
+ private fun animateStuckToTarget(
+ target: MagneticTarget,
+ velX: Float,
+ velY: Float,
+ flung: Boolean,
+ after: (() -> Unit)? = null
+ ) {
+ target.updateLocationOnScreen()
+ getLocationOnScreen(underlyingObject, objectLocationOnScreen)
+
+ // Calculate the difference between the target's center coordinates and the object's.
+ // Animating the object's x/y properties by these values will center the object on top
+ // of the magnetic target.
+ val xDiff = target.centerOnScreen.x -
+ getWidth(underlyingObject) / 2f - objectLocationOnScreen[0]
+ val yDiff = target.centerOnScreen.y -
+ getHeight(underlyingObject) / 2f - objectLocationOnScreen[1]
+
+ val springConfig = if (flung) flungIntoTargetSpringConfig else springConfig
+
+ cancelAnimations()
+
+ // Animate to the center of the target.
+ animator
+ .spring(xProperty, xProperty.getValue(underlyingObject) + xDiff, velX,
+ springConfig)
+ .spring(yProperty, yProperty.getValue(underlyingObject) + yDiff, velY,
+ springConfig)
+
+ if (after != null) {
+ animator.withEndActions(after)
+ }
+
+ animator.start()
+ }
+
+ /**
+ * Whether or not the provided values match a 'fast fling' towards the provided target. If it
+ * does, we consider it a fling-to-target gesture.
+ */
+ private fun isForcefulFlingTowardsTarget(
+ target: MagneticTarget,
+ rawX: Float,
+ rawY: Float,
+ velX: Float,
+ velY: Float
+ ): Boolean {
+ if (!flingToTargetEnabled) {
+ return false
+ }
+
+ // Whether velocity is sufficient, depending on whether we're flinging into a target at the
+ // top or the bottom of the screen.
+ val velocitySufficient =
+ if (rawY < target.centerOnScreen.y) velY > flingToTargetMinVelocity
+ else velY < flingToTargetMinVelocity
+
+ if (!velocitySufficient) {
+ return false
+ }
+
+ // Whether the trajectory of the fling intersects the target area.
+ var targetCenterXIntercept = rawX
+
+ // Only do math if the X velocity is non-zero, otherwise X won't change.
+ if (velX != 0f) {
+ // Rise over run...
+ val slope = velY / velX
+ // ...y = mx + b, b = y / mx...
+ val yIntercept = rawY - slope * rawX
+
+ // ...calculate the x value when y = the target's y-coordinate.
+ targetCenterXIntercept = (target.centerOnScreen.y - yIntercept) / slope
+ }
+
+ // The width of the area we're looking for a fling towards.
+ val targetAreaWidth = target.targetView.width * flingToTargetWidthPercent
+
+ // Velocity was sufficient, so return true if the intercept is within the target area.
+ return targetCenterXIntercept > target.centerOnScreen.x - targetAreaWidth / 2 &&
+ targetCenterXIntercept < target.centerOnScreen.x + targetAreaWidth / 2
+ }
+
+ /** Cancel animations on this object's x/y properties. */
+ internal fun cancelAnimations() {
+ animator.cancel(xProperty, yProperty)
+ }
+
+ /** Updates the locations on screen of all of the [associatedTargets]. */
+ internal fun updateTargetViewLocations() {
+ associatedTargets.forEach { it.updateLocationOnScreen() }
+ }
+
+ /**
+ * Represents a target view with a magnetic field radius and cached center-on-screen
+ * coordinates.
+ *
+ * Instances of MagneticTarget are passed to a MagnetizedObject's [addTarget], and can then
+ * attract the object if it's dragged near or flung towards it. MagneticTargets can be added to
+ * multiple objects.
+ */
+ class MagneticTarget(
+ internal val targetView: View,
+ var magneticFieldRadiusPx: Int
+ ) {
+ internal val centerOnScreen = PointF()
+
+ private val tempLoc = IntArray(2)
+
+ fun updateLocationOnScreen() {
+ targetView.getLocationOnScreen(tempLoc)
+
+ // Add half of the target size to get the center, and subtract translation since the
+ // target could be animating in while we're doing this calculation.
+ centerOnScreen.set(
+ tempLoc[0] + targetView.width / 2f - targetView.translationX,
+ tempLoc[1] + targetView.height / 2f - targetView.translationY)
+ }
+ }
+
+ companion object {
+
+ /**
+ * Magnetizes the given view. Magnetized views are attracted to one or more magnetic
+ * targets. Magnetic targets attract objects that are dragged near them, and hold them there
+ * unless they're moved away or released. Releasing objects inside a magnetic target
+ * typically performs an action on the object.
+ *
+ * Magnetized views can also be flung to targets, which will result in the view being pulled
+ * into the target and released as if it was dragged into it.
+ *
+ * To use the returned MagnetizedObject<View> instance, first set [magnetListener] to
+ * receive event callbacks. In your touch handler, pass all MotionEvents that move this view
+ * to [maybeConsumeMotionEvent]. If that method returns true, consider the event consumed by
+ * MagnetizedObject and don't move the view unless it begins returning false again.
+ *
+ * The view will be moved via translationX/Y properties, and its
+ * width/height will be determined via getWidth()/getHeight(). If you are animating
+ * something other than a view, or want to position your view using properties other than
+ * translationX/Y, implement an instance of [MagnetizedObject].
+ *
+ * Note that the magnetic library can't re-order your view automatically. If the view
+ * renders on top of the target views, it will obscure the target when it sticks to it.
+ * You'll want to bring the view to the front in [MagnetListener.onStuckToTarget].
+ */
+ @JvmStatic
+ fun <T : View> magnetizeView(view: T): MagnetizedObject<T> {
+ return object : MagnetizedObject<T>(
+ view.context,
+ view,
+ DynamicAnimation.TRANSLATION_X,
+ DynamicAnimation.TRANSLATION_Y) {
+ override fun getWidth(underlyingObject: T): Float {
+ return underlyingObject.width.toFloat()
+ }
+
+ override fun getHeight(underlyingObject: T): Float {
+ return underlyingObject.height.toFloat() }
+
+ override fun getLocationOnScreen(underlyingObject: T, loc: IntArray) {
+ underlyingObject.getLocationOnScreen(loc)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java
new file mode 100644
index 000000000000..a94af24fc843
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wifi;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.IAdbManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.EventLog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.CheckBox;
+import android.widget.Toast;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.systemui.R;
+
+/**
+ * Alerts the user of an untrusted network when enabling wireless debugging.
+ * The user can either deny, allow, or allow with the "always allow on this
+ * network" checked.
+ */
+public class WifiDebuggingActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+ private static final String TAG = "WifiDebuggingActivity";
+
+ private CheckBox mAlwaysAllow;
+ // Notifies when wifi is disabled, or the network changed
+ private WifiChangeReceiver mWifiChangeReceiver;
+ private WifiManager mWifiManager;
+ private String mBssid;
+ private boolean mClicked = false;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ Window window = getWindow();
+ window.addSystemFlags(
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+
+ super.onCreate(icicle);
+
+
+ mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mWifiChangeReceiver = new WifiChangeReceiver(this);
+
+ Intent intent = getIntent();
+ String ssid = intent.getStringExtra("ssid");
+ mBssid = intent.getStringExtra("bssid");
+
+ if (ssid == null || mBssid == null) {
+ finish();
+ return;
+ }
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mTitle = getString(R.string.wifi_debugging_title);
+ ap.mMessage = getString(R.string.wifi_debugging_message, ssid, mBssid);
+ ap.mPositiveButtonText = getString(R.string.wifi_debugging_allow);
+ ap.mNegativeButtonText = getString(android.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ // add "always allow" checkbox
+ LayoutInflater inflater = LayoutInflater.from(ap.mContext);
+ View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysAllow = (CheckBox) checkbox.findViewById(com.android.internal.R.id.alwaysUse);
+ mAlwaysAllow.setText(getString(R.string.wifi_debugging_always));
+ ap.mView = checkbox;
+ window.setCloseOnTouchOutside(false);
+
+ setupAlert();
+
+ // adding touch listener on affirmative button - checks if window is obscured
+ // if obscured, do not let user give permissions (could be tapjacking involved)
+ final View.OnTouchListener filterTouchListener = (View v, MotionEvent event) -> {
+ // Filter obscured touches by consuming them.
+ if (((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0)
+ || ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0)) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ // TODO: need a different value for safety net?
+ EventLog.writeEvent(0x534e4554, "62187985"); // safety net logging
+ Toast.makeText(v.getContext(),
+ R.string.touch_filtered_warning,
+ Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ return false;
+ };
+ mAlert.getButton(BUTTON_POSITIVE).setOnTouchListener(filterTouchListener);
+
+ }
+
+ @Override
+ public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
+ super.onWindowAttributesChanged(params);
+ }
+
+ private class WifiChangeReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ WifiChangeReceiver(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+ int state = intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+ if (state == WifiManager.WIFI_STATE_DISABLED) {
+ mActivity.finish();
+ }
+ } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+ NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO);
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ if (!networkInfo.isConnected()) {
+ mActivity.finish();
+ return;
+ }
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ if (wifiInfo == null || wifiInfo.getNetworkId() == -1) {
+ mActivity.finish();
+ return;
+ }
+ String bssid = wifiInfo.getBSSID();
+ if (bssid == null || bssid.isEmpty()) {
+ mActivity.finish();
+ return;
+ }
+ if (!bssid.equals(mBssid)) {
+ mActivity.finish();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ registerReceiver(mWifiChangeReceiver, filter);
+ }
+
+ @Override
+ protected void onStop() {
+ if (mWifiChangeReceiver != null) {
+ unregisterReceiver(mWifiChangeReceiver);
+ }
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // In the case where user dismissed the dialog, we don't get an onClick event.
+ // In that case, tell adb to deny the network connection.
+ if (!mClicked) {
+ try {
+ IBinder b = ServiceManager.getService(ADB_SERVICE);
+ IAdbManager service = IAdbManager.Stub.asInterface(b);
+ service.denyWirelessDebugging();
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to notify Adb service", e);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mClicked = true;
+ boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
+ boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
+ try {
+ IBinder b = ServiceManager.getService(ADB_SERVICE);
+ IAdbManager service = IAdbManager.Stub.asInterface(b);
+ if (allow) {
+ service.allowWirelessDebugging(alwaysAllow, mBssid);
+ } else {
+ service.denyWirelessDebugging();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to notify Adb service", e);
+ }
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
new file mode 100644
index 000000000000..0266a84503a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wifi;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.systemui.R;
+
+/**
+ * Alerts the user that wireless debugging cannot be enabled by a secondary user.
+ */
+public class WifiDebuggingSecondaryUserActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+ private WifiChangeReceiver mWifiChangeReceiver;
+ private WifiManager mWifiManager;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mWifiChangeReceiver = new WifiChangeReceiver(this);
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mTitle = getString(R.string.wifi_debugging_secondary_user_title);
+ ap.mMessage = getString(R.string.wifi_debugging_secondary_user_message);
+ ap.mPositiveButtonText = getString(android.R.string.ok);
+ ap.mPositiveButtonListener = this;
+
+ setupAlert();
+ }
+
+ private class WifiChangeReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ WifiChangeReceiver(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+ int state = intent.getIntExtra(
+ WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+ if (state == WifiManager.WIFI_STATE_DISABLED) {
+ mActivity.finish();
+ }
+ } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+ NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO);
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ if (!networkInfo.isConnected()) {
+ mActivity.finish();
+ return;
+ }
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ if (wifiInfo == null || wifiInfo.getNetworkId() == -1) {
+ mActivity.finish();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ registerReceiver(mWifiChangeReceiver, filter);
+ }
+
+ @Override
+ protected void onStop() {
+ if (mWifiChangeReceiver != null) {
+ unregisterReceiver(mWifiChangeReceiver);
+ }
+ super.onStop();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index befe3e12b64e..6a0939630bf2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -22,6 +22,7 @@ import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -75,6 +76,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@SmallTest
@@ -117,6 +119,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private SubscriptionManager mSubscriptionManager;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private Executor mBackgroundExecutor;
private TestableLooper mTestableLooper;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -137,7 +141,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
when(mUserManager.isPrimaryUser()).thenReturn(true);
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mStrongAuthTracker
+ .isUnlockingWithBiometricAllowed(anyBoolean() /* isStrongBiometric */))
+ .thenReturn(true);
context.addMockSystemService(TrustManager.class, mTrustManager);
context.addMockSystemService(FingerprintManager.class, mFingerprintManager);
context.addMockSystemService(BiometricManager.class, mBiometricManager);
@@ -450,7 +456,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() {
- mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
+ // test whether face will be skipped if authenticated, so the value of isStrongBiometric
+ // doesn't matter here
+ mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser(),
+ true /* isStrongBiometric */);
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
@@ -460,18 +469,36 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testGetUserCanSkipBouncer_whenFace() {
int user = KeyguardUpdateMonitor.getCurrentUser();
- mKeyguardUpdateMonitor.onFaceAuthenticated(user);
+ mKeyguardUpdateMonitor.onFaceAuthenticated(user, true /* isStrongBiometric */);
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
}
@Test
+ public void testGetUserCanSkipBouncer_whenFace_nonStrongAndDisallowed() {
+ when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+ .thenReturn(false);
+ int user = KeyguardUpdateMonitor.getCurrentUser();
+ mKeyguardUpdateMonitor.onFaceAuthenticated(user, false /* isStrongBiometric */);
+ assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
+ }
+
+ @Test
public void testGetUserCanSkipBouncer_whenFingerprint() {
int user = KeyguardUpdateMonitor.getCurrentUser();
- mKeyguardUpdateMonitor.onFingerprintAuthenticated(user);
+ mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, true /* isStrongBiometric */);
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
}
@Test
+ public void testGetUserCanSkipBouncer_whenFingerprint_nonStrongAndDisallowed() {
+ when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+ .thenReturn(false);
+ int user = KeyguardUpdateMonitor.getCurrentUser();
+ mKeyguardUpdateMonitor.onFingerprintAuthenticated(user, false /* isStrongBiometric */);
+ assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
+ }
+
+ @Test
public void testGetUserCanSkipBouncer_whenTrust() {
int user = KeyguardUpdateMonitor.getCurrentUser();
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */);
@@ -585,7 +612,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
protected TestableKeyguardUpdateMonitor(Context context) {
super(context,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
- mBroadcastDispatcher, mDumpController);
+ mBroadcastDispatcher, mDumpController, mBackgroundExecutor);
mStrongAuthTracker = KeyguardUpdateMonitorTest.this.mStrongAuthTracker;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 3330d1e6d0a8..61991816a407 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -93,6 +93,8 @@ public final class ClockManagerTest extends SysuiTestCase {
mMockPluginManager, mMockColorExtractor, mMockContentResolver,
mMockCurrentUserObserable, mMockSettingsWrapper, mFakeDockManager);
+ mClockManager.addBuiltinClock(() -> new BubbleClockController(
+ getContext().getResources(), inflater, mMockColorExtractor));
mClockManager.addOnClockChangedListener(mMockListener1);
mClockManager.addOnClockChangedListener(mMockListener2);
reset(mMockListener1, mMockListener2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 1d4b4be9e683..581d795af3df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -124,7 +125,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index b3d0d22445b6..6388fe1a69c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -63,7 +63,7 @@ class NotificationSectionsFeatureManagerTest : SysuiTestCase() {
DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false)
assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled())
- assertTrue("Expecting 3 buckets when people filtering is enabled",
- manager!!.getNumberOfBuckets() == 3)
+ assertTrue("Expecting 4 buckets when people filtering is enabled",
+ manager!!.getNumberOfBuckets() == 4)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 45c51d42c250..f11c42bda6cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -32,6 +32,7 @@ import com.android.systemui.statusbar.notification.NotificationFilter
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -148,6 +149,53 @@ class NotificationRankingManagerTest : SysuiTestCase() {
}
@Test
+ fun testSort_headsUp_trumpsPeople() {
+ whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
+ val aN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val a = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(aN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+
+ whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(true)
+ whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(true)
+
+ val bN = Notification.Builder(mContext, "test")
+ .setStyle(Notification.MessagingStyle(""))
+ .build()
+ val b = NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .setPkg("pkg2")
+ .setOpPkg("pkg2")
+ .setTag("tag")
+ .setNotification(bN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build()
+ b.row = mock(ExpandableNotificationRow::class.java).also {
+ whenever(it.isHeadsUp).thenReturn(true)
+ }
+
+ whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(false)
+ whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking))
+ .thenReturn(false)
+
+ assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test"))
+ }
+
+ @Test
fun testSort_importantPeople() {
whenever(sectionsManager.isFilteringEnabled()).thenReturn(true)
val aN = Notification.Builder(mContext, "test")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index 867a9b97d622..abce8b517dfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -43,7 +43,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() {
@JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
- @Mock private lateinit var mockViewBoundary: PeopleHubSectionFooterViewBoundary
+ @Mock private lateinit var mockViewBoundary: PeopleHubViewBoundary
@Mock private lateinit var mockActivityStarter: ActivityStarter
@Test
@@ -67,7 +67,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() {
return mockSubscription
}
}
- val adapter = PeopleHubSectionFooterViewAdapterImpl(fakeFactoryDataSource)
+ val adapter = PeopleHubViewAdapterImpl(fakeFactoryDataSource)
adapter.bindView(mockViewBoundary)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 51f214d8cda2..abfbcd99167b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -45,8 +45,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -71,7 +70,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
@Mock private ActivityStarterDelegate mActivityStarterDelegate;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private ConfigurationController mConfigurationController;
- @Mock private PeopleHubSectionFooterViewAdapter mPeopleHubAdapter;
+ @Mock private PeopleHubViewAdapter mPeopleHubAdapter;
@Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
@Mock private NotificationRowComponent mNotificationRowComponent;
@Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
@@ -90,18 +89,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
mStatusBarStateController,
mConfigurationController,
mPeopleHubAdapter,
- mSectionsFeatureManager,
- new NotificationRowComponent.Builder() {
- @Override
- public NotificationRowComponent.Builder activatableNotificationView(
- ActivatableNotificationView view) {
- return this;
- }
-
- @Override
- public NotificationRowComponent build() {
- return mNotificationRowComponent;
- }});
+ mSectionsFeatureManager
+ );
// Required in order for the header inflation to work properly
when(mNssl.generateLayoutParams(any(AttributeSet.class)))
.thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 769b774aeec2..813923d44216 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -97,7 +97,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
- when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+ when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
+ .thenReturn(true);
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mContext.addMockSystemService(PowerManager.class, mPowerManager);
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
@@ -112,11 +113,28 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
@Test
public void onBiometricAuthenticated_whenFingerprintAndBiometricsDisallowed_showBouncer() {
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */))
+ .thenReturn(false);
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FINGERPRINT);
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
anyFloat());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
+ }
+
+ @Test
+ public void onBiometricAuthenticated_whenFingerprint_nonStrongBioDisallowed_showBouncer() {
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */))
+ .thenReturn(false);
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */);
+ verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
+ verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
+ anyFloat());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
}
@Test
@@ -124,44 +142,60 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
reset(mUpdateMonitor);
reset(mStatusBarKeyguardViewManager);
when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mDozeScrimController.isPulsing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FINGERPRINT);
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
}
@Test
public void onBiometricAuthenticated_whenFingerprint_dismissKeyguard() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FINGERPRINT);
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
anyFloat());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
}
@Test
public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FINGERPRINT);
+ BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
}
@Test
public void onBiometricAuthenticated_whenFace_dontDismissKeyguard() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_NONE);
}
@Test
@@ -169,13 +203,17 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
anyBoolean(), anyFloat());
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
}
@Test
@@ -184,9 +222,11 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
// Wake up before showing the bouncer
verify(mStatusBarKeyguardViewManager, never()).showBouncer(eq(false));
@@ -202,9 +242,11 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
reset(mUpdateMonitor);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
@@ -215,23 +257,30 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
@Test
public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
}
@Test
public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
reset(mKeyguardBypassController);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
- when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+ when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
+ .thenReturn(true);
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
@@ -240,11 +289,13 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
@Test
public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
@@ -255,13 +306,17 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
reset(mUpdateMonitor);
reset(mStatusBarKeyguardViewManager);
- when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mDozeScrimController.isPulsing()).thenReturn(true);
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
anyBoolean(), anyFloat());
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_ONLY_WAKE);
}
@Test
@@ -270,8 +325,10 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onFinishedGoingToSleep(-1);
verify(mHandler, never()).post(any());
+ // the value of isStrongBiometric doesn't matter here since we only care about the returned
+ // value of isUnlockingWithBiometricAllowed()
mBiometricUnlockController.onBiometricAuthenticated(1 /* userId */,
- BiometricSourceType.FACE);
+ BiometricSourceType.FACE, true /* isStrongBiometric */);
mBiometricUnlockController.onFinishedGoingToSleep(-1);
verify(mHandler).post(any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 2e6fbe7d1ddb..408dfc0e1dee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -36,7 +36,6 @@ import static org.mockito.Mockito.when;
import android.animation.Animator;
import android.app.AlarmManager;
-import android.content.res.Resources;
import android.graphics.Color;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
@@ -91,8 +90,6 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock
LightBarController mLightBarController;
@Mock
- Resources mResources;
- @Mock
DelayedWakeLock.Builder mDelayedWakeLockBuilder;
@Mock
private DelayedWakeLock mWakeLock;
@@ -216,8 +213,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
- mDozeParamenters, mAlarmManager, mKeyguardStateController,
- mResources, mDelayedWakeLockBuilder,
+ mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
mDockManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
new file mode 100644
index 000000000000..f1672b1c644d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.magnetictarget
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import android.view.View
+import androidx.dynamicanimation.animation.FloatPropertyCompat
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.PhysicsAnimatorTestUtils
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MagnetizedObjectTest : SysuiTestCase() {
+ /** Incrementing value for fake MotionEvent timestamps. */
+ private var time = 0L
+
+ /** Value to add to each new MotionEvent's timestamp. */
+ private var timeStep = 100
+
+ private val underlyingObject = this
+
+ private lateinit var targetView: View
+
+ private val targetSize = 200
+ private val targetCenterX = 500
+ private val targetCenterY = 900
+ private val magneticFieldRadius = 200
+
+ private var objectX = 0f
+ private var objectY = 0f
+ private val objectSize = 50f
+
+ private lateinit var magneticTarget: MagnetizedObject.MagneticTarget
+ private lateinit var magnetizedObject: MagnetizedObject<*>
+ private lateinit var magnetListener: MagnetizedObject.MagnetListener
+
+ private val xProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+ override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+ objectX = value
+ }
+ override fun getValue(target: MagnetizedObjectTest?): Float {
+ return objectX
+ }
+ }
+
+ private val yProperty = object : FloatPropertyCompat<MagnetizedObjectTest>("") {
+ override fun setValue(target: MagnetizedObjectTest?, value: Float) {
+ objectY = value
+ }
+
+ override fun getValue(target: MagnetizedObjectTest?): Float {
+ return objectY
+ }
+ }
+
+ @Before
+ fun setup() {
+ PhysicsAnimatorTestUtils.prepareForTest()
+
+ // Mock the view since a real view's getLocationOnScreen() won't work unless it's attached
+ // to a real window (it'll always return x = 0, y = 0).
+ targetView = mock(View::class.java)
+ `when`(targetView.context).thenReturn(context)
+
+ // The mock target view will pretend that it's 200x200, and at (400, 800). This means it's
+ // occupying the bounds (400, 800, 600, 1000) and it has a center of (500, 900).
+ `when`(targetView.width).thenReturn(targetSize) // width = 200
+ `when`(targetView.height).thenReturn(targetSize) // height = 200
+ doAnswer { invocation ->
+ (invocation.arguments[0] as IntArray).also { location ->
+ // Return the top left of the target.
+ location[0] = targetCenterX - targetSize / 2 // x = 400
+ location[1] = targetCenterY - targetSize / 2 // y = 800
+ }
+ }.`when`(targetView).getLocationOnScreen(ArgumentMatchers.any())
+ `when`(targetView.context).thenReturn(context)
+
+ magneticTarget = MagnetizedObject.MagneticTarget(targetView, magneticFieldRadius)
+
+ magnetListener = mock(MagnetizedObject.MagnetListener::class.java)
+ magnetizedObject = object : MagnetizedObject<MagnetizedObjectTest>(
+ context, underlyingObject, xProperty, yProperty) {
+ override fun getWidth(underlyingObject: MagnetizedObjectTest): Float {
+ return objectSize
+ }
+
+ override fun getHeight(underlyingObject: MagnetizedObjectTest): Float {
+ return objectSize
+ }
+
+ override fun getLocationOnScreen(
+ underlyingObject: MagnetizedObjectTest,
+ loc: IntArray
+ ) {
+ loc[0] = objectX.toInt()
+ loc[1] = objectY.toInt() }
+ }
+
+ magnetizedObject.magnetListener = magnetListener
+ magnetizedObject.addTarget(magneticTarget)
+
+ timeStep = 100
+ }
+
+ @Test
+ fun testMotionEventConsumption() {
+ // Start at (0, 0). No magnetic field here.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0, action = MotionEvent.ACTION_DOWN)))
+
+ // Move to (400, 400), which is solidly outside the magnetic field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 200, y = 200)))
+
+ // Move to (305, 705). This would be in the magnetic field radius if magnetic fields were
+ // square. It's not, because they're not.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX - magneticFieldRadius + 5,
+ y = targetCenterY - magneticFieldRadius + 5)))
+
+ // Move to (400, 800). That's solidly in the radius so the magnetic target should begin
+ // consuming events.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX - 100,
+ y = targetCenterY - 100)))
+
+ // Release at (400, 800). Since we're in the magnetic target, it should return true and
+ // consume the ACTION_UP.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 400, y = 800, action = MotionEvent.ACTION_UP)))
+
+ // ACTION_DOWN outside the field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 200, y = 200, action = MotionEvent.ACTION_DOWN)))
+
+ // Move to the center. We absolutely should consume events there.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY)))
+
+ // Drag out to (0, 0) and we should be returning false again.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0)))
+
+ // The ACTION_UP event shouldn't be consumed either since it's outside the field.
+ assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = 0, y = 0, action = MotionEvent.ACTION_UP)))
+ }
+
+ @Test
+ fun testMotionEventConsumption_downInMagneticField() {
+ // We should consume DOWN events if they occur in the field.
+ assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN)))
+ }
+
+ @Test
+ fun testMoveIntoAroundAndOutOfMagneticField() {
+ // Move around but don't touch the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 100),
+ getMotionEvent(x = 200, y = 200))
+
+ // You can't become unstuck if you were never stuck in the first place.
+ verify(magnetListener, never()).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+
+ // Move into and then around inside the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+ getMotionEvent(x = targetCenterX, y = targetCenterY),
+ getMotionEvent(x = targetCenterX + 100, y = targetCenterY + 100))
+
+ // We should only have received one call to onStuckToTarget and none to unstuck.
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+
+ // Move out of the field and then release.
+ dispatchMotionEvents(
+ getMotionEvent(x = 100, y = 100),
+ getMotionEvent(x = 100, y = 100, action = MotionEvent.ACTION_UP))
+
+ // We should have received one unstuck call and no more stuck calls. We also should never
+ // have received an onReleasedInTarget call.
+ verify(magnetListener, times(1)).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMoveIntoOutOfAndBackIntoMagneticField() {
+ // Move into the field
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX - magneticFieldRadius,
+ y = targetCenterY - magneticFieldRadius,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX, y = targetCenterY))
+
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+ // Move back out.
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX - magneticFieldRadius,
+ y = targetCenterY - magneticFieldRadius))
+
+ verify(magnetListener, times(1)).onUnstuckFromTarget(
+ eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
+ eq(false))
+ verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
+
+ // Move in again and release in the magnetic field.
+ dispatchMotionEvents(
+ getMotionEvent(x = targetCenterX - 100, y = targetCenterY - 100),
+ getMotionEvent(x = targetCenterX + 50, y = targetCenterY + 50),
+ getMotionEvent(x = targetCenterX, y = targetCenterY),
+ getMotionEvent(
+ x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_UP))
+
+ verify(magnetListener, times(2)).onStuckToTarget(magneticTarget)
+ verify(magnetListener).onReleasedInTarget(magneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_towardsTarget() {
+ timeStep = 10
+
+ // Forcefully fling the object towards the target (but never touch the magnetic field).
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ // Nevertheless it should have ended up stuck to the target.
+ verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_towardsButTooSlow() {
+ // Very, very slowly fling the object towards the target (but never touch the magnetic
+ // field). This value is only used to create MotionEvent timestamps, it will not block the
+ // test for 10 seconds.
+ timeStep = 10000
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = targetCenterX,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ // No sticking should have occurred.
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testFlingTowardsTarget_missTarget() {
+ timeStep = 10
+ // Forcefully fling the object down, but not towards the target.
+ dispatchMotionEvents(
+ getMotionEvent(
+ x = 0,
+ y = 0,
+ action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(
+ x = 0,
+ y = targetCenterY / 2),
+ getMotionEvent(
+ x = 0,
+ y = targetCenterY - magneticFieldRadius * 2,
+ action = MotionEvent.ACTION_UP))
+
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMagnetAnimation() {
+ // Make sure the object starts at (0, 0).
+ assertEquals(0f, objectX)
+ assertEquals(0f, objectY)
+
+ // Trigger the magnet animation, and block the test until it ends.
+ PhysicsAnimatorTestUtils.setAllAnimationsBlock(true)
+ magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+ x = targetCenterX,
+ y = targetCenterY,
+ action = MotionEvent.ACTION_DOWN))
+
+ // The object's (top-left) position should now position it centered over the target.
+ assertEquals(targetCenterX - objectSize / 2, objectX)
+ assertEquals(targetCenterY - objectSize / 2, objectY)
+ }
+
+ @Test
+ fun testMultipleTargets() {
+ val secondMagneticTarget = getSecondMagneticTarget()
+
+ // Drag into the second target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 900))
+
+ // Verify that we received an onStuck for the second target, and no others.
+ verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+
+ // Drag into the original target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 0, y = 0),
+ getMotionEvent(x = 500, y = 900))
+
+ // We should have unstuck from the second one and stuck into the original one.
+ verify(magnetListener).onUnstuckFromTarget(
+ eq(secondMagneticTarget), anyFloat(), anyFloat(), eq(false))
+ verify(magnetListener).onStuckToTarget(magneticTarget)
+ verifyNoMoreInteractions(magnetListener)
+ }
+
+ @Test
+ fun testMultipleTargets_flingIntoSecond() {
+ val secondMagneticTarget = getSecondMagneticTarget()
+
+ timeStep = 10
+
+ // Fling towards the second target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 100, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 100, y = 350),
+ getMotionEvent(x = 100, y = 650, action = MotionEvent.ACTION_UP))
+
+ // Verify that we received an onStuck for the second target.
+ verify(magnetListener).onStuckToTarget(secondMagneticTarget)
+
+ // Fling towards the first target.
+ dispatchMotionEvents(
+ getMotionEvent(x = 300, y = 0, action = MotionEvent.ACTION_DOWN),
+ getMotionEvent(x = 400, y = 350),
+ getMotionEvent(x = 500, y = 650, action = MotionEvent.ACTION_UP))
+
+ // Verify that we received onStuck for the original target.
+ verify(magnetListener).onStuckToTarget(magneticTarget)
+ }
+
+ private fun getSecondMagneticTarget(): MagnetizedObject.MagneticTarget {
+ // The first target view is at bounds (400, 800, 600, 1000) and it has a center of
+ // (500, 900). We'll add a second one at bounds (0, 800, 200, 1000) with center (100, 900).
+ val secondTargetView = mock(View::class.java)
+ var secondTargetCenterX = 100
+ var secondTargetCenterY = 900
+
+ `when`(secondTargetView.context).thenReturn(context)
+ `when`(secondTargetView.width).thenReturn(targetSize) // width = 200
+ `when`(secondTargetView.height).thenReturn(targetSize) // height = 200
+ doAnswer { invocation ->
+ (invocation.arguments[0] as IntArray).also { location ->
+ // Return the top left of the target.
+ location[0] = secondTargetCenterX - targetSize / 2 // x = 0
+ location[1] = secondTargetCenterY - targetSize / 2 // y = 800
+ }
+ }.`when`(secondTargetView).getLocationOnScreen(ArgumentMatchers.any())
+
+ return magnetizedObject.addTarget(secondTargetView, magneticFieldRadius)
+ }
+
+ /**
+ * Return a MotionEvent at the given coordinates, with the given action (or MOVE by default).
+ * The event's time fields will be incremented by 10ms each time this is called, so tha
+ * VelocityTracker works.
+ */
+ private fun getMotionEvent(
+ x: Int,
+ y: Int,
+ action: Int = MotionEvent.ACTION_MOVE
+ ): MotionEvent {
+ return MotionEvent.obtain(time, time, action, x.toFloat(), y.toFloat(), 0)
+ .also { time += timeStep }
+ }
+
+ /** Dispatch all of the provided events to the target view. */
+ private fun dispatchMotionEvents(vararg events: MotionEvent) {
+ events.forEach { magnetizedObject.maybeConsumeMotionEvent(it) }
+ }
+
+ /** Prevents Kotlin from being mad that eq() is nullable. */
+ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+} \ 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
index df87ac994d42..a18f5da60cad 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -33,6 +33,9 @@ import android.os.ResultReceiver;
*/
@SystemApi(client = MODULE_LIBRARIES)
public class TetheringConstants {
+ /** An explicit private class to avoid exposing constructor.*/
+ private TetheringConstants() { }
+
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index f9ef0b7b8e9d..a4bea661583b 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -11,6 +11,7 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libRS \
libcutils \
+ libhwui \
liblog \
libutils \
libui \
diff --git a/services/Android.bp b/services/Android.bp
index db6e21a62ff3..ef47867eed48 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -29,6 +29,7 @@ filegroup {
":services.usage-sources",
":services.usb-sources",
":services.voiceinteraction-sources",
+ ":services.wifi-sources",
":service-permission-sources",
":service-statsd-sources",
],
@@ -71,6 +72,7 @@ java_library {
"services.usage",
"services.usb",
"services.voiceinteraction",
+ "services.wifi",
"android.hidl.base-V1.0-java",
],
diff --git a/services/api/current.txt b/services/api/current.txt
index 26a65f21ed83..4a0a0d8e5aef 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -74,3 +74,12 @@ package com.android.server {
}
+package com.android.server.wifi {
+
+ public class SupplicantManager {
+ method public static void start();
+ method public static void stop();
+ }
+
+}
+
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f544517a79e3..317ce4cb5fee 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1158,6 +1158,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to hide fill UI", e);
}
+ try {
+ final InlineSuggestionSession.ImeResponse imeResponse =
+ mInlineSuggestionSession.waitAndGetImeResponse();
+ if (imeResponse == null) {
+ Log.w(TAG, "Session input method callback is not set yet");
+ return;
+ }
+ imeResponse.getCallback().onInlineSuggestionsResponse(
+ new InlineSuggestionsResponse(Collections.EMPTY_LIST));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException hiding inline suggestions");
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index a8886fc06c5a..0d8c89b4124d 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -72,32 +72,35 @@ public final class InlineSuggestionFactory {
*/
public static InlineSuggestionsResponse createInlineSuggestionsResponse(
@NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
- @Nullable String filterText,
- @Nullable List<InlinePresentation> inlineActions,
- @NonNull AutofillId autofillId,
- @NonNull Context context,
- @NonNull AutoFillUI.AutoFillUiCallback client,
- @NonNull Runnable onErrorCallback,
+ @Nullable String filterText, @Nullable List<InlinePresentation> inlineActions,
+ @NonNull AutofillId autofillId, @NonNull Context context,
+ @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
final BiConsumer<Dataset, Integer> onClickFactory;
if (response.getAuthentication() != null) {
- onClickFactory = (dataset, datasetIndex) -> client.authenticate(response.getRequestId(),
- datasetIndex, response.getAuthentication(), response.getClientState(),
- /* authenticateInline= */ true);
+ onClickFactory = (dataset, datasetIndex) -> {
+ client.requestHideFillUi(autofillId);
+ client.authenticate(response.getRequestId(),
+ datasetIndex, response.getAuthentication(), response.getClientState(),
+ /* authenticateInline= */ true);
+ };
} else {
- onClickFactory = (dataset, datasetIndex) ->
- client.fill(response.getRequestId(), datasetIndex, dataset);
+ onClickFactory = (dataset, datasetIndex) -> {
+ client.requestHideFillUi(autofillId);
+ client.fill(response.getRequestId(), datasetIndex, dataset);
+ };
}
final List<Dataset> datasetList = response.getDatasets();
final Dataset[] datasets = datasetList == null
? null
: datasetList.toArray(new Dataset[]{});
-
- return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request, response,
- datasets, filterText, inlineActions, autofillId, context, onErrorCallback,
- onClickFactory, remoteRenderService);
+ final InlinePresentation inlineAuthentication =
+ response.getAuthentication() == null ? null : response.getInlinePresentation();
+ return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
+ datasets, filterText, inlineAuthentication, inlineActions, autofillId, context,
+ onErrorCallback, onClickFactory, remoteRenderService);
}
/**
@@ -105,33 +108,31 @@ public final class InlineSuggestionFactory {
* autofill service.
*/
public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
- @NonNull InlineSuggestionsRequest request,
- @NonNull Dataset[] datasets,
- @NonNull AutofillId autofillId,
- @NonNull Context context,
+ @NonNull InlineSuggestionsRequest request, @NonNull Dataset[] datasets,
+ @NonNull AutofillId autofillId, @NonNull Context context,
@NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
@NonNull Runnable onErrorCallback,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
- /* fillResponse= */ null, datasets, /* filterText= */ null,
+ datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
/* inlineActions= */ null, autofillId, context, onErrorCallback,
- (dataset, fieldIndex) ->
+ (dataset, datasetIndex) ->
inlineSuggestionUiCallback.autofill(dataset), remoteRenderService);
}
private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal(
boolean isAugmented, @NonNull InlineSuggestionsRequest request,
- @Nullable FillResponse response, @Nullable Dataset[] datasets,
- @Nullable String filterText,
+ @Nullable Dataset[] datasets, @Nullable String filterText,
+ @Nullable InlinePresentation inlineAuthentication,
@Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId,
@NonNull Context context, @NonNull Runnable onErrorCallback,
@NonNull BiConsumer<Dataset, Integer> onClickFactory,
@Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
- if (response.getAuthentication() != null) {
- InlineSuggestion inlineAuthSuggestion = createInlineAuthSuggestion(response,
+ if (inlineAuthentication != null) {
+ InlineSuggestion inlineAuthSuggestion = createInlineAuthSuggestion(inlineAuthentication,
remoteRenderService, onClickFactory, onErrorCallback,
request.getHostInputToken());
inlineSuggestions.add(inlineAuthSuggestion);
@@ -250,11 +251,11 @@ public final class InlineSuggestionFactory {
return inlineSuggestion;
}
- private static InlineSuggestion createInlineAuthSuggestion(@NonNull FillResponse response,
+ private static InlineSuggestion createInlineAuthSuggestion(
+ @NonNull InlinePresentation inlinePresentation,
@NonNull RemoteInlineSuggestionRenderService remoteRenderService,
@NonNull BiConsumer<Dataset, Integer> onClickFactory, @NonNull Runnable onErrorCallback,
@Nullable IBinder hostInputToken) {
- final InlinePresentation inlinePresentation = response.getInlinePresentation();
final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
inlinePresentation.getInlinePresentationSpec(),
InlineSuggestionInfo.SOURCE_AUTOFILL, null, InlineSuggestionInfo.TYPE_SUGGESTION);
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 0bcf45d4a526..5e10916c4491 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -47,7 +47,6 @@ 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;
@@ -400,12 +399,6 @@ 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/core/Android.bp b/services/core/Android.bp
index 228d9bebaae6..4da60b8e4ffd 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -126,6 +126,7 @@ java_library_static {
"android.hidl.manager-V1.2-java",
"dnsresolver_aidl_interface-V2-java",
"netd_event_listener_interface-java",
+ "ike-stubs",
],
plugins: [
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 0f8d57e3d9e3..8b2bfa10a029 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -237,6 +237,33 @@ public abstract class PackageManagerInternal {
public abstract boolean isPackageSuspended(String packageName, int userId);
/**
+ * Removes all package suspensions imposed by any non-system packages.
+ */
+ public abstract void removeAllNonSystemPackageSuspensions(int userId);
+
+ /**
+ * Removes all suspensions imposed on the given package by non-system packages.
+ */
+ public abstract void removeNonSystemPackageSuspensions(String packageName, int userId);
+
+ /**
+ * Removes all {@link PackageManager.DistractionRestriction restrictions} set on the given
+ * package
+ */
+ public abstract void removeDistractingPackageRestrictions(String packageName, int userId);
+
+ /**
+ * Removes all {@link PackageManager.DistractionRestriction restrictions} set on all the
+ * packages.
+ */
+ public abstract void removeAllDistractingPackageRestrictions(int userId);
+
+ /**
+ * Flushes package restrictions for the given user immediately to disk.
+ */
+ public abstract void flushPackageRestrictions(int userId);
+
+ /**
* Get the name of the package that suspended the given package. Packages can be suspended by
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
* {@link android.Manifest.permission#SUSPEND_APPS}.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e48ef5a528be..f84d35fb7776 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3302,7 +3302,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
final NetworkRequestInfo nri = mNetworkRequests.get(request);
- ensureRunningOnConnectivityServiceThread();
final NetworkAgentInfo currentNetwork = nri.mSatisfier;
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
nri.mSatisfier = null;
@@ -3454,18 +3453,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then it is needed.
- ensureRunningOnConnectivityServiceThread();
if (nri.request.isRequest() && nai.satisfies(nri.request) &&
- (nai.isSatisfyingRequest(nri.request.requestId)
- // Note that canPossiblyBeat catches two important cases:
- // 1. Unvalidated slow networks will not be reaped when an unvalidated fast
- // network is currently satisfying the request. This is desirable for example
- // when cellular ends up validating but WiFi/Ethernet does not.
- // 2. Fast networks will not be reaped when a validated slow network is
- // currently satisfying the request. This is desirable for example when
- // Ethernet ends up validating and out scoring WiFi, or WiFi/Ethernet ends
- // up validating and out scoring cellular.
- || nai.canPossiblyBeat(nri.mSatisfier))) {
+ (nai.isSatisfyingRequest(nri.request.requestId) ||
+ // Note that this catches two important cases:
+ // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+ // is currently satisfying the request. This is desirable when
+ // cellular ends up validating but WiFi does not.
+ // 2. Unvalidated WiFi will not be reaped when validated cellular
+ // is currently satisfying the request. This is desirable when
+ // WiFi ends up validating and out scoring cellular.
+ nri.mSatisfier.getCurrentScore()
+ < nai.getCurrentScoreAsValidated())) {
return false;
}
}
@@ -3493,7 +3491,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (mNetworkRequests.get(nri.request) == null) {
return;
}
- ensureRunningOnConnectivityServiceThread();
if (nri.mSatisfier != null) {
return;
}
@@ -3531,7 +3528,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
boolean wasKept = false;
- ensureRunningOnConnectivityServiceThread();
final NetworkAgentInfo nai = nri.mSatisfier;
if (nai != null) {
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
@@ -3843,9 +3839,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
return avoidBadWifi();
}
+
private void rematchForAvoidBadWifiUpdate() {
- ensureRunningOnConnectivityServiceThread();
- mixInAllNetworkScores();
rematchAllNetworksAndRequests();
for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
@@ -7071,45 +7066,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- /**
- * Re-mixin all network scores.
- * This is called when some global setting like avoidBadWifi has changed.
- * TODO : remove this when all usages have been removed.
- */
- private void mixInAllNetworkScores() {
- ensureRunningOnConnectivityServiceThread();
- for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- nai.setNetworkScore(mixInNetworkScore(nai, nai.getNetworkScore()));
- }
- }
-
- /**
- * Mix in the Connectivity-managed parts of the NetworkScore.
- * @param nai The NAI this score applies to.
- * @param sourceScore the score sent by the network agent, or the previous score of this NAI.
- * @return A new score with the Connectivity-managed parts mixed in.
- */
- @NonNull
- private NetworkScore mixInNetworkScore(@NonNull final NetworkAgentInfo nai,
- @NonNull final NetworkScore sourceScore) {
- final NetworkScore.Builder score = new NetworkScore.Builder(sourceScore);
-
- // TODO : this should be done in Telephony. It should be handled per-network because
- // it's a carrier-dependent config.
- if (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
- if (mMultinetworkPolicyTracker.getAvoidBadWifi()) {
- score.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI);
- } else {
- score.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI);
- }
- }
-
- return score.build();
- }
-
private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + ns);
- nai.setNetworkScore(mixInNetworkScore(nai, ns));
+ nai.setNetworkScore(ns);
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5db5115b4afe..2804d79ef56f 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -149,7 +149,13 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void onStart() {
+ // enable client caches by doing the first invalidate
+ LocationManager.invalidateLocalLocationEnabledCaches();
+
publishBinderService(Context.LOCATION_SERVICE, mService);
+ // disable caching for whatever process contains LocationManagerService
+ ((LocationManager) mService.mContext.getSystemService(LocationManager.class))
+ .disableLocalLocationEnabledCaches();
}
@Override
@@ -439,6 +445,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private void onLocationModeChanged(int userId) {
boolean enabled = mSettingsHelper.isLocationEnabled(userId);
+ LocationManager.invalidateLocalLocationEnabledCaches();
if (D) {
Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
@@ -862,10 +869,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- public void requestSetAllowed(boolean allowed) {
- mProvider.requestSetAllowed(allowed);
- }
-
public void onUserStarted(int userId) {
synchronized (mLock) {
// clear the user's enabled state in order to force a reevalution of whether the
@@ -2538,6 +2541,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS,
"Requires WRITE_SECURE_SETTINGS permission");
+
+ LocationManager.invalidateLocalLocationEnabledCaches();
mSettingsHelper.setLocationEnabled(enabled, userId);
}
@@ -2931,18 +2936,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private class LocalService extends LocationManagerInternal {
@Override
- public void requestSetProviderAllowed(String provider, boolean allowed) {
- Preconditions.checkArgument(provider != null, "invalid null provider");
-
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager != null) {
- manager.requestSetAllowed(allowed);
- }
- }
- }
-
- @Override
public boolean isProviderEnabledForUser(@NonNull String provider, int userId) {
synchronized (mLock) {
LocationProviderManager manager = getLocationProviderManager(provider);
diff --git a/services/core/java/com/android/server/MemoryPressureUtil.java b/services/core/java/com/android/server/MemoryPressureUtil.java
new file mode 100644
index 000000000000..c34dc2f5a9b1
--- /dev/null
+++ b/services/core/java/com/android/server/MemoryPressureUtil.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+import android.os.StrictMode;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+
+/**
+ * Utility method for memory pressure (PSI).
+ */
+public final class MemoryPressureUtil {
+ private static final String FILE = "/proc/pressure/memory";
+ private static final String TAG = "MemoryPressure";
+
+ /**
+ * @return a stanza about memory PSI to add to a report.
+ */
+ public static String currentPsiState() {
+ final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+ StringWriter contents = new StringWriter();
+ try {
+ if (new File(FILE).exists()) {
+ contents.append("----- Output from /proc/pressure/memory -----\n");
+ contents.append(IoUtils.readFileAsString(FILE));
+ contents.append("----- End output from /proc/pressure/memory -----\n\n");
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not read " + FILE, e);
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
+ }
+ return contents.toString();
+ }
+
+ private MemoryPressureUtil(){}
+}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 179780d88084..8f914fe6f59f 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -175,6 +175,6 @@ public class SystemServerInitThreadPool {
final ArrayList<Integer> pids = new ArrayList<>();
pids.add(Process.myPid());
ActivityManagerService.dumpStackTraces(pids, null, null,
- Watchdog.getInterestingNativePids());
+ Watchdog.getInterestingNativePids(), null);
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 8900eee6f50f..ac7867f29a79 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -50,6 +50,7 @@ import com.android.server.wm.SurfaceAnimationThread;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -583,7 +584,7 @@ public class Watchdog extends Thread {
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
ActivityManagerService.dumpStackTraces(pids, null, null,
- getInterestingNativePids());
+ getInterestingNativePids(), null);
waitedHalf = true;
}
continue;
@@ -609,16 +610,21 @@ public class Watchdog extends Thread {
if (mPhonePid > 0) pids.add(mPhonePid);
long anrTime = SystemClock.uptimeMillis();
+ StringBuilder report = new StringBuilder();
+ report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false);
+ StringWriter tracesFileException = new StringWriter();
final File stack = ActivityManagerService.dumpStackTraces(
- pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids());
+ pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids(),
+ tracesFileException);
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.
SystemClock.sleep(5000);
processCpuTracker.update();
- String cpuInfo = processCpuTracker.printCurrentState(anrTime);
+ report.append(processCpuTracker.printCurrentState(anrTime));
+ report.append(tracesFileException.getBuffer());
// Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
doSysRq('w');
@@ -634,7 +640,7 @@ public class Watchdog extends Thread {
if (mActivity != null) {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null, null,
- subject, cpuInfo, stack, null);
+ subject, report.toString(), stack, null);
}
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED,
subject);
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index f2a8615dca88..0d161b943d15 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -134,9 +134,13 @@ public class AdbService extends IAdbManager.Stub {
mIsAdbWifiEnabled = false;
// register observer to listen for settings changes
+ mObserver = new AdbSettingsObserver();
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
- false, new AdbSettingsObserver());
+ false, mObserver);
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
+ false, mObserver);
} catch (Exception e) {
Slog.e(TAG, "Error in initAdbState", e);
}
@@ -153,6 +157,7 @@ public class AdbService extends IAdbManager.Stub {
private class AdbSettingsObserver extends ContentObserver {
private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED);
+ private final Uri mAdbWifiUri = Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED);
AdbSettingsObserver() {
super(null);
@@ -166,8 +171,13 @@ public class AdbService extends IAdbManager.Stub {
FgThread.getHandler().sendMessage(obtainMessage(
AdbService::setAdbEnabled, AdbService.this, shouldEnable,
AdbTransportType.USB));
+ } else if (mAdbWifiUri.equals(uri)) {
+ boolean shouldEnable = (Settings.Global.getInt(mContentResolver,
+ Settings.Global.ADB_WIFI_ENABLED, 0) > 0);
+ FgThread.getHandler().sendMessage(obtainMessage(
+ AdbService::setAdbEnabled, AdbService.this, shouldEnable,
+ AdbTransportType.WIFI));
}
- // TODO(joshuaduong): Add condition for WIFI transport
}
}
@@ -188,6 +198,8 @@ public class AdbService extends IAdbManager.Stub {
private boolean mIsAdbWifiEnabled;
private AdbDebuggingManager mDebuggingManager;
+ private ContentObserver mObserver;
+
private AdbService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -213,6 +225,8 @@ public class AdbService extends IAdbManager.Stub {
try {
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_ENABLED, mIsAdbUsbEnabled ? 1 : 0);
+ Settings.Global.putInt(mContentResolver,
+ Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0);
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
Slog.d(TAG, "ADB_ENABLED is restricted.");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d8eff5c11cc..6c0623021025 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3851,10 +3851,11 @@ public class ActivityManagerService extends IActivityManager.Stub
* @param firstPids of dalvik VM processes to dump stack traces for first
* @param lastPids of dalvik VM processes to dump stack traces for last
* @param nativePids optional list of native pids to dump stack crawls
+ * @param logExceptionCreatingFile optional writer to which we log errors creating the file
*/
public static File dumpStackTraces(ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
- ArrayList<Integer> nativePids) {
+ ArrayList<Integer> nativePids, StringWriter logExceptionCreatingFile) {
ArrayList<Integer> extraPids = null;
Slog.i(TAG, "dumpStackTraces pids=" + lastPids + " nativepids=" + nativePids);
@@ -3894,8 +3895,15 @@ public class ActivityManagerService extends IActivityManager.Stub
// NOTE: We should consider creating the file in native code atomically once we've
// gotten rid of the old scheme of dumping and lot of the code that deals with paths
// can be removed.
- File tracesFile = createAnrDumpFile(tracesDir);
- if (tracesFile == null) {
+ File tracesFile;
+ try {
+ tracesFile = createAnrDumpFile(tracesDir);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception creating ANR dump file:", e);
+ if (logExceptionCreatingFile != null) {
+ logExceptionCreatingFile.append("----- Exception creating ANR dump file -----\n");
+ e.printStackTrace(new PrintWriter(logExceptionCreatingFile));
+ }
return null;
}
@@ -3906,7 +3914,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("ActivityManagerService.class")
private static SimpleDateFormat sAnrFileDateFormat;
- private static synchronized File createAnrDumpFile(File tracesDir) {
+ private static synchronized File createAnrDumpFile(File tracesDir) throws IOException {
if (sAnrFileDateFormat == null) {
sAnrFileDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
}
@@ -3914,18 +3922,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final String formattedDate = sAnrFileDateFormat.format(new Date());
final File anrFile = new File(tracesDir, "anr_" + formattedDate);
- try {
- if (anrFile.createNewFile()) {
- FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw-------
- return anrFile;
- } else {
- Slog.w(TAG, "Unable to create ANR dump file: createNewFile failed");
- }
- } catch (IOException ioe) {
- Slog.w(TAG, "Exception creating ANR dump file:", ioe);
+ if (anrFile.createNewFile()) {
+ FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw-------
+ return anrFile;
+ } else {
+ throw new IOException("Unable to create ANR dump file: createNewFile failed");
}
-
- return null;
}
/**
@@ -7271,7 +7273,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Wait for the provider to be published...
final long timeout =
- SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS;
+ SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
while (cpr.provider == null) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index a2ae6786d95d..c239feb155c6 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1128,6 +1128,7 @@ public final class OomAdjuster {
app.setCurRawAdj(app.maxAdj);
app.setHasForegroundActivities(false);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
+ app.curCapability = PROCESS_CAPABILITY_ALL;
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e63da9b1e80b..c2f03ec8d6c4 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -66,11 +66,13 @@ import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.Zygote;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.MemoryPressureUtil;
import com.android.server.wm.WindowProcessController;
import com.android.server.wm.WindowProcessListener;
import java.io.File;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -1581,6 +1583,8 @@ class ProcessRecord implements WindowProcessListener {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
+ StringBuilder report = new StringBuilder();
+ report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
// don't dump native PIDs for background ANRs unless it is the process of interest
@@ -1608,19 +1612,20 @@ class ProcessRecord implements WindowProcessListener {
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
+ StringWriter tracesFileException = new StringWriter();
File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
(isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,
- nativePids);
+ nativePids, tracesFileException);
- String cpuInfo = null;
if (isMonitorCpuUsage()) {
mService.updateCpuStatsNow();
synchronized (mService.mProcessCpuTracker) {
- cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
+ report.append(mService.mProcessCpuTracker.printCurrentState(anrTime));
}
info.append(processCpuTracker.printCurrentLoad());
- info.append(cpuInfo);
+ info.append(report);
}
+ report.append(tracesFileException.getBuffer());
info.append(processCpuTracker.printCurrentState(anrTime));
@@ -1645,7 +1650,8 @@ class ProcessRecord implements WindowProcessListener {
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
- parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
+ parentShortComponentName, parentPr, annotation, report.toString(), tracesFile,
+ null);
if (mWindowProcessController.appNotResponding(info.toString(), () -> kill("anr",
ApplicationExitInfo.REASON_ANR, true),
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 5d8a0f6161cd..4670d58ca63b 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -401,10 +401,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts=");
pw.println(mHasStartedWhitelistingBgActivityStarts);
}
- if (mAllowWhileInUsePermissionInFgs) {
- pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
- pw.println(mAllowWhileInUsePermissionInFgs);
- }
+ pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
+ pw.println(mAllowWhileInUsePermissionInFgs);
+ pw.print(prefix); pw.print("recentCallingPackage=");
+ pw.println(mRecentCallingPackage);
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 204f072a72fc..8ed221d943ef 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -311,6 +311,7 @@ public class AuthService extends SystemService {
}
authenticator = new FingerprintAuthenticator(fingerprintService);
+ fingerprintService.initConfiguredStrength(config.mStrength);
break;
case TYPE_FACE:
@@ -322,6 +323,7 @@ public class AuthService extends SystemService {
}
authenticator = new FaceAuthenticator(faceService);
+ faceService.initConfiguredStrength(config.mStrength);
break;
case TYPE_IRIS:
@@ -333,6 +335,7 @@ public class AuthService extends SystemService {
}
authenticator = new IrisAuthenticator(irisService);
+ irisService.initConfiguredStrength(config.mStrength);
break;
default:
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 0e709944b03f..74c70df6224c 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -31,6 +31,7 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricNativeHandle;
import android.hardware.biometrics.IBiometricService;
@@ -106,6 +107,7 @@ public abstract class BiometricServiceBase extends SystemService
private PerformanceStats mPerformanceStats;
protected int mCurrentUserId = UserHandle.USER_NULL;
protected long mHalDeviceId;
+ private int mOEMStrength; // Tracks the OEM configured biometric modality strength
// Tracks if the current authentication makes use of CryptoObjects.
protected boolean mIsCrypto;
// Normal authentications are tracked by mPerformanceMap.
@@ -681,6 +683,20 @@ public abstract class BiometricServiceBase extends SystemService
statsModality(), BiometricsProtoEnums.ISSUE_HAL_DEATH);
}
+ protected void initConfiguredStrengthInternal(int strength) {
+ if (DEBUG) {
+ Slog.d(getTag(), "initConfiguredStrengthInternal(" + strength + ")");
+ }
+ mOEMStrength = strength;
+ }
+
+ protected boolean isStrongBiometric() {
+ // TODO(b/141025588): need to calculate actual strength when downgrading tiers
+ final int biometricBits = mOEMStrength
+ & BiometricManager.Authenticators.BIOMETRIC_MIN_STRENGTH;
+ return biometricBits == BiometricManager.Authenticators.BIOMETRIC_STRONG;
+ }
+
protected ClientMonitor getCurrentClient() {
return mCurrentClient;
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 31c3d4d7b24e..a87a455fa2c1 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -740,6 +740,12 @@ public class FaceService extends BiometricServiceBase {
}
return 0;
}
+
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
}
/**
@@ -809,7 +815,7 @@ public class FaceService extends BiometricServiceBase {
if (mFaceServiceReceiver != null) {
if (biometric == null || biometric instanceof Face) {
mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric,
- userId);
+ userId, isStrongBiometric());
} else {
Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric");
}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 0a6198863b00..83aa9cf5ad2c 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
@@ -462,6 +463,12 @@ public class FingerprintService extends BiometricServiceBase {
checkPermission(MANAGE_FINGERPRINT);
mClientActiveCallbacks.remove(callback);
}
+
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
}
/**
@@ -526,8 +533,8 @@ public class FingerprintService extends BiometricServiceBase {
throws RemoteException {
if (mFingerprintServiceReceiver != null) {
if (biometric == null || biometric instanceof Fingerprint) {
- mFingerprintServiceReceiver
- .onAuthenticationSucceeded(deviceId, (Fingerprint) biometric, userId);
+ mFingerprintServiceReceiver.onAuthenticationSucceeded(deviceId,
+ (Fingerprint) biometric, userId, isStrongBiometric());
} else {
Slog.e(TAG, "onAuthenticationSucceeded received non-fingerprint biometric");
}
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
index 2817315ac175..903ae6b205b9 100644
--- a/services/core/java/com/android/server/biometrics/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -16,9 +16,12 @@
package com.android.server.biometrics.iris;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.iris.IIrisService;
import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
@@ -42,6 +45,17 @@ public class IrisService extends BiometricServiceBase {
private static final String TAG = "IrisService";
/**
+ * Receives the incoming binder calls from IrisManager.
+ */
+ private final class IrisServiceWrapper extends IIrisService.Stub {
+ @Override // Binder call
+ public void initConfiguredStrength(int strength) {
+ checkPermission(USE_BIOMETRIC_INTERNAL);
+ initConfiguredStrengthInternal(strength);
+ }
+ }
+
+ /**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
@@ -57,6 +71,7 @@ public class IrisService extends BiometricServiceBase {
@Override
public void onStart() {
super.onStart();
+ publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper());
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 3860904a3fed..4612cfd0f7cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,8 +16,6 @@
package com.android.server.connectivity;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.transportNamesOf;
import android.annotation.NonNull;
@@ -477,16 +475,24 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
- /** Gets the current score */
- public int getCurrentScore() {
+ private int getCurrentScore(boolean pretendValidated) {
+ // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
+ // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
+ // score. The NetworkScore class would provide a nice place to centralize score constants
+ // so they are not scattered about the transports.
+
// If this network is explicitly selected and the user has decided to use it even if it's
- // unvalidated, give it the maximum score.
- if (networkAgentConfig.explicitlySelected && networkAgentConfig.acceptUnvalidated) {
+ // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
+ // selected and we're trying to see what its score could be. This ensures that we don't tear
+ // down an explicitly selected network before the user gets a chance to prefer it when
+ // a higher-scoring network (e.g., Ethernet) is available.
+ if (networkAgentConfig.explicitlySelected
+ && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
int score = mNetworkScore.getLegacyScore();
- if (!lastValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
+ if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
if (score < 0) score = 0;
@@ -502,6 +508,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return isWifi && !avoidBadWifi && everValidated;
}
+ // Get the current score for this Network. This may be modified from what the
+ // NetworkAgent sent, as it has modifiers applied to it.
+ public int getCurrentScore() {
+ return getCurrentScore(false);
+ }
+
+ // Get the current score for this Network as if it was validated. This may be modified from
+ // what the NetworkAgent sent, as it has modifiers applied to it.
+ public int getCurrentScoreAsValidated() {
+ return getCurrentScore(true);
+ }
+
public void setNetworkScore(@NonNull NetworkScore ns) {
mNetworkScore = ns;
}
@@ -611,41 +629,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mLingering = false;
}
- /**
- * Returns whether this NAI has any chance of ever beating this other agent.
- *
- * The chief use case of this is the decision to tear down this network. ConnectivityService
- * tears down networks that don't satisfy any request, unless they have a chance to beat any
- * existing satisfier.
- *
- * @param other the agent to beat
- * @return whether this should be given more time to try and beat the other agent
- * TODO : remove this and migrate to a ranker-based approach
- */
- public boolean canPossiblyBeat(@NonNull final NetworkAgentInfo other) {
- // Any explicitly selected network should be held on.
- if (networkAgentConfig.explicitlySelected) return true;
- // An outscored exiting network should be torn down.
- if (mNetworkScore.isExiting()) return false;
- // If this network is validated it can be torn down as it can't hope to be better than
- // it already is.
- if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) return false;
- // If neither network is validated, keep both until at least one does.
- if (!other.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) return true;
- // If this network is not metered but the other is, it should be preferable if it validates.
- if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !other.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
- return true;
- }
-
- // If the control comes here :
- // • This network is neither exiting or explicitly selected
- // • This network is not validated, but the other is
- // • This network is metered, or both networks are unmetered
- // Keep it if it's expected to be faster than the other., should it validate.
- return mNetworkScore.probablyFasterThan(other.mNetworkScore);
- }
-
public void dumpLingerTimers(PrintWriter pw) {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java
index 80d46e0370b4..d0aabf95d572 100644
--- a/services/core/java/com/android/server/connectivity/NetworkRanker.java
+++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java
@@ -16,19 +16,10 @@
package com.android.server.connectivity;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkScore.POLICY_IGNORE_ON_WIFI;
-
-import static com.android.internal.util.FunctionalUtils.findFirst;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import java.util.ArrayList;
import java.util.Collection;
/**
@@ -40,75 +31,20 @@ public class NetworkRanker {
/**
* Find the best network satisfying this request among the list of passed networks.
*/
+ // Almost equivalent to Collections.max(nais), but allows returning null if no network
+ // satisfies the request.
@Nullable
public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request,
@NonNull final Collection<NetworkAgentInfo> nais) {
- final ArrayList<NetworkAgentInfo> candidates = new ArrayList<>(nais);
- candidates.removeIf(nai -> !nai.satisfies(request));
-
- // Enforce policy. The order in which the policy is computed is essential, because each
- // step may remove some of the candidates. For example, filterValidated drops non-validated
- // networks in presence of validated networks for INTERNET requests, but the bad wifi
- // avoidance policy takes priority over this, so it must be done before.
- filterVpn(candidates);
- filterExplicitlySelected(candidates);
- filterBadWifiAvoidance(candidates);
- filterValidated(request, candidates);
-
NetworkAgentInfo bestNetwork = null;
int bestScore = Integer.MIN_VALUE;
- for (final NetworkAgentInfo nai : candidates) {
- final int score = nai.getNetworkScore().getLegacyScore();
- if (score > bestScore) {
+ for (final NetworkAgentInfo nai : nais) {
+ if (!nai.satisfies(request)) continue;
+ if (nai.getCurrentScore() > bestScore) {
bestNetwork = nai;
- bestScore = score;
+ bestScore = nai.getCurrentScore();
}
}
return bestNetwork;
}
-
- // If a network is a VPN it has priority.
- private void filterVpn(@NonNull final ArrayList<NetworkAgentInfo> candidates) {
- final NetworkAgentInfo vpn = findFirst(candidates,
- nai -> nai.networkCapabilities.hasTransport(TRANSPORT_VPN));
- if (null == vpn) return; // No VPN : this policy doesn't apply.
- candidates.removeIf(nai -> !nai.networkCapabilities.hasTransport(TRANSPORT_VPN));
- }
-
- // If some network is explicitly selected and set to accept unvalidated connectivity, then
- // drop all networks that are not explicitly selected.
- private void filterExplicitlySelected(
- @NonNull final ArrayList<NetworkAgentInfo> candidates) {
- final NetworkAgentInfo explicitlySelected = findFirst(candidates,
- nai -> nai.networkAgentConfig.explicitlySelected
- && nai.networkAgentConfig.acceptUnvalidated);
- if (null == explicitlySelected) return; // No explicitly selected network accepting unvalid
- candidates.removeIf(nai -> !nai.networkAgentConfig.explicitlySelected);
- }
-
- // If some network with wifi transport is present, drop all networks with POLICY_IGNORE_ON_WIFI.
- private void filterBadWifiAvoidance(@NonNull final ArrayList<NetworkAgentInfo> candidates) {
- final NetworkAgentInfo wifi = findFirst(candidates,
- nai -> nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
- && nai.everValidated
- // Horrible hack : there is old UI that will let a user say they want to
- // override the policy only for this network only at this time and it
- // feeds into the following member. This old UI should probably be removed
- // but for now keep backward compatibility.
- && !nai.avoidUnvalidated);
- if (null == wifi) return; // No wifi : this policy doesn't apply
- candidates.removeIf(nai -> nai.getNetworkScore().hasPolicy(POLICY_IGNORE_ON_WIFI));
- }
-
- // If some network is validated and the request asks for INTERNET, drop all networks that are
- // not validated.
- private void filterValidated(@NonNull final NetworkRequest request,
- @NonNull final ArrayList<NetworkAgentInfo> candidates) {
- if (!request.hasCapability(NET_CAPABILITY_INTERNET)) return;
- final NetworkAgentInfo validated = findFirst(candidates,
- nai -> nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
- if (null == validated) return; // No validated network
- candidates.removeIf(nai ->
- !nai.networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED));
- }
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 8bbeabf779d2..7cb84585a57c 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -73,7 +73,7 @@ public class DisplayModeDirector {
private static final int GLOBAL_ID = -1;
// The tolerance within which we consider something approximately equals.
- private static final float EPSILON = 0.01f;
+ private static final float FLOAT_TOLERANCE = 0.01f;
private final Object mLock = new Object();
private final Context mContext;
@@ -267,8 +267,8 @@ public class DisplayModeDirector {
// Some refresh rates are calculated based on frame timings, so they aren't *exactly*
// equal to expected refresh rate. Given that, we apply a bit of tolerance to this
// comparison.
- if (refreshRate < (minRefreshRate - EPSILON)
- || refreshRate > (maxRefreshRate + EPSILON)) {
+ if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
+ || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ ", outside refresh rate bounds"
@@ -487,12 +487,18 @@ public class DisplayModeDirector {
public RefreshRateRange() {}
public RefreshRateRange(float min, float max) {
- if (min < 0 || max < 0 || min > max) {
+ if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+ min + " " + max);
this.min = this.max = 0;
return;
}
+ if (min > max) {
+ // Min and max are within epsilon of each other, but in the wrong order.
+ float t = min;
+ min = max;
+ max = t;
+ }
this.min = min;
this.max = max;
}
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 433ec435c8d1..e9d94a5430fe 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -366,21 +366,6 @@ public abstract class AbstractLocationProvider {
protected abstract void onExtraCommand(int uid, int pid, String command, Bundle extras);
/**
- * Requests a provider to enable itself for the given user id.
- */
- public final void requestSetAllowed(boolean allowed) {
- // all calls into the provider must be moved onto the provider thread to prevent deadlock
- mExecutor.execute(
- obtainRunnable(AbstractLocationProvider::onRequestSetAllowed, this, allowed)
- .recycleOnUse());
- }
-
- /**
- * Always invoked on the provider executor.
- */
- protected abstract void onRequestSetAllowed(boolean allowed);
-
- /**
* Dumps debug or log information. May be invoked from any thread.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5f44e042b5e9..685fb9eb38f5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1229,11 +1229,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- @Override
- protected void onRequestSetAllowed(boolean allowed) {
- // do nothing - the gnss provider is always allowed
- }
-
private void deleteAidingData(Bundle extras) {
int flags;
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 96ffaa6c0bff..87208a7f36f5 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -205,14 +205,6 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
- public void onRequestSetAllowed(boolean allowed) {
- mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.requestSetAllowed(allowed);
- });
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mServiceWatcher.dump(fd, pw, args);
}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index b45b66017062..5ec06ca25581 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -64,11 +64,6 @@ public class MockProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {
- setAllowed(allowed);
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("last mock location=" + mLocation);
}
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index f43669e488d1..0f358e97bc98 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -224,15 +224,6 @@ public class MockableLocationProvider extends AbstractLocationProvider {
}
}
- @Override
- protected void onRequestSetAllowed(boolean allowed) {
- synchronized (mOwnerLock) {
- if (mProvider != null) {
- mProvider.onRequestSetAllowed(allowed);
- }
- }
- }
-
/**
* Dumps the current provider implementation.
*/
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 54dffff8b1df..1ba38cc4d999 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -79,10 +79,5 @@ public class PassiveProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {
- // do nothing - the passive provider is always allowed
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1f4048f821e5..15dfab93ed27 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
+import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.READ_CONTACTS;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -178,6 +179,7 @@ import javax.crypto.spec.GCMParameterSpec;
public class LockSettingsService extends ILockSettings.Stub {
private static final String TAG = "LockSettingsService";
private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+ private static final String BIOMETRIC_PERMISSION = MANAGE_BIOMETRIC;
private static final boolean DEBUG = false;
private static final int PROFILE_KEY_IV_SIZE = 12;
@@ -1050,6 +1052,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ private final void checkBiometricPermission() {
+ mContext.enforceCallingOrSelfPermission(BIOMETRIC_PERMISSION, "LockSettingsBiometric");
+ }
+
@Override
public boolean hasSecureLockScreen() {
return mHasSecureLockScreen;
@@ -2304,6 +2310,18 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
+ public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ checkBiometricPermission();
+ mStrongAuth.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
+ }
+
+ @Override
+ public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+ checkBiometricPermission();
+ mStrongAuth.scheduleNonStrongBiometricIdleTimeout(userId);
+ }
+
+ @Override
public void userPresent(int userId) {
checkWritePermission(userId);
mStrongAuth.reportUnlock(userId);
@@ -3191,6 +3209,12 @@ public class LockSettingsService extends ILockSettings.Stub {
mStorage.dump(pw);
pw.println();
pw.decreaseIndent();
+
+ pw.println("StrongAuth:");
+ pw.increaseIndent();
+ mStrongAuth.dump(pw);
+ pw.println();
+ pw.decreaseIndent();
}
/**
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 91cf53ee9a1f..fbee6f4bcbf0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import android.app.AlarmManager;
@@ -32,8 +33,10 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
/**
@@ -42,6 +45,7 @@ import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
public class LockSettingsStrongAuth {
private static final String TAG = "LockSettings";
+ private static final boolean DEBUG = false;
private static final int MSG_REQUIRE_STRONG_AUTH = 1;
private static final int MSG_REGISTER_TRACKER = 2;
@@ -49,15 +53,40 @@ public class LockSettingsStrongAuth {
private static final int MSG_REMOVE_USER = 4;
private static final int MSG_SCHEDULE_STRONG_AUTH_TIMEOUT = 5;
private static final int MSG_NO_LONGER_REQUIRE_STRONG_AUTH = 6;
+ private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
+ private static final int MSG_STRONG_BIOMETRIC_UNLOCK = 8;
+ private static final int MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT = 9;
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
+ private static final String NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG =
+ "LockSettingsPrimaryAuth.nonStrongBiometricTimeoutForUser";
+ private static final String NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG =
+ "LockSettingsPrimaryAuth.nonStrongBiometricIdleTimeoutForUser";
+
+ /**
+ * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
+ * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+ */
+ public static final long DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS = 24 * 60 * 60 * 1000; // 24h
+ public static final long DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS =
+ 4 * 60 * 60 * 1000; // 4h
private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+ private final SparseBooleanArray mIsNonStrongBiometricAllowedForUser = new SparseBooleanArray();
private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
+ // Track non-strong biometric timeout
+ private final ArrayMap<Integer, NonStrongBiometricTimeoutAlarmListener>
+ mNonStrongBiometricTimeoutAlarmListener = new ArrayMap<>();
+ // Track non-strong biometric idle timeout
+ private final ArrayMap<Integer, NonStrongBiometricIdleTimeoutAlarmListener>
+ mNonStrongBiometricIdleTimeoutAlarmListener = new ArrayMap<>();
+
private final int mDefaultStrongAuthFlags;
+ private final boolean mDefaultIsNonStrongBiometricAllowed = true;
+
private final Context mContext;
private AlarmManager mAlarmManager;
@@ -80,6 +109,17 @@ public class LockSettingsStrongAuth {
Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
}
}
+
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+ try {
+ tracker.onIsNonStrongBiometricAllowedChanged(value, key);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while adding StrongAuthTracker: "
+ + "IsNonStrongBiometricAllowedChanged.", e);
+ }
+ }
}
private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -134,6 +174,13 @@ public class LockSettingsStrongAuth {
mStrongAuthForUser.removeAt(index);
notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
}
+
+ index = mIsNonStrongBiometricAllowedForUser.indexOfKey(userId);
+ if (index >= 0) {
+ mIsNonStrongBiometricAllowedForUser.removeAt(index);
+ notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(
+ mDefaultIsNonStrongBiometricAllowed, userId);
+ }
}
private void handleScheduleStrongAuthTimeout(int userId) {
@@ -151,6 +198,125 @@ public class LockSettingsStrongAuth {
// schedule a new alarm listener for the user
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, STRONG_AUTH_TIMEOUT_ALARM_TAG,
alarm, mHandler);
+
+ // cancel current non-strong biometric alarm listener for the user (if there was one)
+ cancelNonStrongBiometricAlarmListener(userId);
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ // re-allow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(true, userId);
+ }
+
+ private void handleScheduleNonStrongBiometricTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricTimeout for userId=" + userId);
+ long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_TIMEOUT_MS;
+ NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+ .get(userId);
+ if (alarm != null) {
+ // Unlock with non-strong biometric will not affect the existing non-strong biometric
+ // timeout alarm
+ if (DEBUG) {
+ Slog.d(TAG, "There is an existing alarm for non-strong biometric"
+ + " fallback timeout, so do not re-schedule");
+ }
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Schedule a new alarm for non-strong biometric fallback timeout");
+ }
+ alarm = new NonStrongBiometricTimeoutAlarmListener(userId);
+ mNonStrongBiometricTimeoutAlarmListener.put(userId, alarm);
+ // schedule a new alarm listener for the user
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+ NON_STRONG_BIOMETRIC_TIMEOUT_ALARM_TAG, alarm, mHandler);
+ }
+
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ }
+
+ private void handleStrongBiometricUnlock(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleStrongBiometricUnlock for userId=" + userId);
+ // cancel current non-strong biometric alarm listener for the user (if there was one)
+ cancelNonStrongBiometricAlarmListener(userId);
+ // cancel current non-strong biometric idle alarm listener for the user (if there was one)
+ cancelNonStrongBiometricIdleAlarmListener(userId);
+ // re-allow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(true, userId);
+ }
+
+ private void cancelNonStrongBiometricAlarmListener(int userId) {
+ if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricAlarmListener for userId=" + userId);
+ NonStrongBiometricTimeoutAlarmListener alarm = mNonStrongBiometricTimeoutAlarmListener
+ .get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric fallback timeout");
+ mAlarmManager.cancel(alarm);
+ // need to remove the alarm when cancelled by primary auth or strong biometric
+ mNonStrongBiometricTimeoutAlarmListener.remove(userId);
+ }
+ }
+
+ private void cancelNonStrongBiometricIdleAlarmListener(int userId) {
+ if (DEBUG) Slog.d(TAG, "cancelNonStrongBiometricIdleAlarmListener for userId=" + userId);
+ // cancel idle alarm listener by any unlocks (i.e. primary auth, strong biometric,
+ // non-strong biometric)
+ NonStrongBiometricIdleTimeoutAlarmListener alarm =
+ mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel alarm for non-strong biometric idle timeout");
+ mAlarmManager.cancel(alarm);
+ }
+ }
+
+ private void setIsNonStrongBiometricAllowed(boolean allowed, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "setIsNonStrongBiometricAllowed for allowed=" + allowed
+ + ", userId=" + userId);
+ }
+ if (userId == UserHandle.USER_ALL) {
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ setIsNonStrongBiometricAllowedOneUser(allowed, key);
+ }
+ } else {
+ setIsNonStrongBiometricAllowedOneUser(allowed, userId);
+ }
+ }
+
+ private void setIsNonStrongBiometricAllowedOneUser(boolean allowed, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "setIsNonStrongBiometricAllowedOneUser for allowed=" + allowed
+ + ", userId=" + userId);
+ }
+ boolean oldValue = mIsNonStrongBiometricAllowedForUser.get(userId,
+ mDefaultIsNonStrongBiometricAllowed);
+ if (allowed != oldValue) {
+ if (DEBUG) {
+ Slog.d(TAG, "mIsNonStrongBiometricAllowedForUser value changed:"
+ + " oldValue=" + oldValue + ", allowed=" + allowed);
+ }
+ mIsNonStrongBiometricAllowedForUser.put(userId, allowed);
+ notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(allowed, userId);
+ }
+ }
+
+ private void handleScheduleNonStrongBiometricIdleTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "handleScheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+ long when = SystemClock.elapsedRealtime() + DEFAULT_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_MS;
+ // cancel current alarm listener for the user (if there was one)
+ NonStrongBiometricIdleTimeoutAlarmListener alarm =
+ mNonStrongBiometricIdleTimeoutAlarmListener.get(userId);
+ if (alarm != null) {
+ if (DEBUG) Slog.d(TAG, "Cancel existing alarm for non-strong biometric idle timeout");
+ mAlarmManager.cancel(alarm);
+ } else {
+ alarm = new NonStrongBiometricIdleTimeoutAlarmListener(userId);
+ mNonStrongBiometricIdleTimeoutAlarmListener.put(userId, alarm);
+ }
+ // schedule a new alarm listener for the user
+ if (DEBUG) Slog.d(TAG, "Schedule a new alarm for non-strong biometric idle timeout");
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when,
+ NON_STRONG_BIOMETRIC_IDLE_TIMEOUT_ALARM_TAG, alarm, mHandler);
}
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
@@ -170,6 +336,29 @@ public class LockSettingsStrongAuth {
}
}
+ private void notifyStrongAuthTrackersForIsNonStrongBiometricAllowed(boolean allowed,
+ int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyStrongAuthTrackersForIsNonStrongBiometricAllowed"
+ + " for allowed=" + allowed + ", userId=" + userId);
+ }
+ int i = mTrackers.beginBroadcast();
+ try {
+ while (i > 0) {
+ i--;
+ try {
+ mTrackers.getBroadcastItem(i).onIsNonStrongBiometricAllowedChanged(
+ allowed, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker: "
+ + "IsNonStrongBiometricAllowedChanged.", e);
+ }
+ }
+ } finally {
+ mTrackers.finishBroadcast();
+ }
+ }
+
public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
}
@@ -207,11 +396,45 @@ public class LockSettingsStrongAuth {
requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
}
+ /**
+ * Report successful unlocking with primary auth
+ */
public void reportSuccessfulStrongAuthUnlock(int userId) {
final int argNotUsed = 0;
mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
}
+ /**
+ * Report successful unlocking with biometric
+ */
+ public void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "reportSuccessfulBiometricUnlock for isStrongBiometric="
+ + isStrongBiometric + ", userId=" + userId);
+ }
+ final int argNotUsed = 0;
+ if (isStrongBiometric) { // unlock with strong biometric
+ mHandler.obtainMessage(MSG_STRONG_BIOMETRIC_UNLOCK, userId, argNotUsed)
+ .sendToTarget();
+ } else { // unlock with non-strong biometric (i.e. weak or convenience)
+ mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT, userId, argNotUsed)
+ .sendToTarget();
+ }
+ }
+
+ /**
+ * Schedule idle timeout for non-strong biometric (i.e. weak or convenience)
+ */
+ public void scheduleNonStrongBiometricIdleTimeout(int userId) {
+ if (DEBUG) Slog.d(TAG, "scheduleNonStrongBiometricIdleTimeout for userId=" + userId);
+ final int argNotUsed = 0;
+ mHandler.obtainMessage(MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT, userId, argNotUsed)
+ .sendToTarget();
+ }
+
+ /**
+ * Alarm of fallback timeout for primary auth
+ */
private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
private final int mUserId;
@@ -226,6 +449,41 @@ public class LockSettingsStrongAuth {
}
}
+ /**
+ * Alarm of fallback timeout for non-strong biometric (i.e. weak or convenience)
+ */
+ private class NonStrongBiometricTimeoutAlarmListener implements OnAlarmListener {
+
+ private final int mUserId;
+
+ NonStrongBiometricTimeoutAlarmListener(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onAlarm() {
+ requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT, mUserId);
+ }
+ }
+
+ /**
+ * Alarm of idle timeout for non-strong biometric (i.e. weak or convenience biometric)
+ */
+ private class NonStrongBiometricIdleTimeoutAlarmListener implements OnAlarmListener {
+
+ private final int mUserId;
+
+ NonStrongBiometricIdleTimeoutAlarmListener(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onAlarm() {
+ // disallow unlock with non-strong biometrics
+ setIsNonStrongBiometricAllowed(false, mUserId);
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -248,8 +506,38 @@ public class LockSettingsStrongAuth {
case MSG_NO_LONGER_REQUIRE_STRONG_AUTH:
handleNoLongerRequireStrongAuth(msg.arg1, msg.arg2);
break;
+ case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_TIMEOUT:
+ handleScheduleNonStrongBiometricTimeout(msg.arg1);
+ break;
+ case MSG_STRONG_BIOMETRIC_UNLOCK:
+ handleStrongBiometricUnlock(msg.arg1);
+ break;
+ case MSG_SCHEDULE_NON_STRONG_BIOMETRIC_IDLE_TIMEOUT:
+ handleScheduleNonStrongBiometricIdleTimeout(msg.arg1);
+ break;
}
}
};
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("PrimaryAuthFlags state:");
+ pw.increaseIndent();
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ final int key = mStrongAuthForUser.keyAt(i);
+ final int value = mStrongAuthForUser.valueAt(i);
+ pw.println("userId=" + key + ", primaryAuthFlags=" + Integer.toHexString(value));
+ }
+ pw.println();
+ pw.decreaseIndent();
+
+ pw.println("NonStrongBiometricAllowed state:");
+ pw.increaseIndent();
+ for (int i = 0; i < mIsNonStrongBiometricAllowedForUser.size(); i++) {
+ final int key = mIsNonStrongBiometricAllowedForUser.keyAt(i);
+ final boolean value = mIsNonStrongBiometricAllowedForUser.valueAt(i);
+ pw.println("userId=" + key + ", allowed=" + value);
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 33e01bd21105..265b9ad10561 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -213,7 +213,8 @@ class BluetoothRouteProvider {
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
- .setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH)
+ //TODO: Set type correctly (BLUETOOTH_A2DP or HEARING_AID)
+ .setType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)
.setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.build();
newBtRoute.connectedProfiles = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 9b1824f7d7aa..f144405436f9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -53,15 +53,15 @@ abstract class MediaRoute2Provider {
public abstract void requestCreateSession(String packageName, String routeId, long requestId,
@Nullable Bundle sessionHints);
- public abstract void releaseSession(String sessionId);
+ public abstract void releaseSession(String sessionId, long requestId);
public abstract void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference);
- public abstract void selectRoute(String sessionId, String routeId);
- public abstract void deselectRoute(String sessionId, String routeId);
- public abstract void transferToRoute(String sessionId, String routeId);
+ public abstract void selectRoute(String sessionId, String routeId, long requestId);
+ public abstract void deselectRoute(String sessionId, String routeId, long requestId);
+ public abstract void transferToRoute(String sessionId, String routeId, long requestId);
- public abstract void setRouteVolume(String routeId, int volume);
- public abstract void setSessionVolume(String sessionId, int volume);
+ public abstract void setRouteVolume(String routeId, int volume, long requestId);
+ public abstract void setSessionVolume(String sessionId, int volume, long requestId);
@NonNull
public String getUniqueId() {
@@ -116,5 +116,6 @@ abstract class MediaRoute2Provider {
@NonNull RoutingSessionInfo sessionInfo);
void onSessionReleased(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo);
+ void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId, int reason);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 60934e0cdfc6..e64776cc6e35 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -87,9 +87,9 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void releaseSession(String sessionId) {
+ public void releaseSession(String sessionId, long requestId) {
if (mConnectionReady) {
- mActiveConnection.releaseSession(sessionId);
+ mActiveConnection.releaseSession(sessionId, requestId);
updateBinding();
}
}
@@ -103,38 +103,38 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
- public void selectRoute(String sessionId, String routeId) {
+ public void selectRoute(String sessionId, String routeId, long requestId) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(sessionId, routeId);
+ mActiveConnection.selectRoute(sessionId, routeId, requestId);
}
}
@Override
- public void deselectRoute(String sessionId, String routeId) {
+ public void deselectRoute(String sessionId, String routeId, long requestId) {
if (mConnectionReady) {
- mActiveConnection.deselectRoute(sessionId, routeId);
+ mActiveConnection.deselectRoute(sessionId, routeId, requestId);
}
}
@Override
- public void transferToRoute(String sessionId, String routeId) {
+ public void transferToRoute(String sessionId, String routeId, long requestId) {
if (mConnectionReady) {
- mActiveConnection.transferToRoute(sessionId, routeId);
+ mActiveConnection.transferToRoute(sessionId, routeId, requestId);
}
}
@Override
- public void setRouteVolume(String routeId, int volume) {
+ public void setRouteVolume(String routeId, int volume, long requestId) {
if (mConnectionReady) {
- mActiveConnection.setRouteVolume(routeId, volume);
+ mActiveConnection.setRouteVolume(routeId, volume, requestId);
updateBinding();
}
}
@Override
- public void setSessionVolume(String sessionId, int volume) {
+ public void setSessionVolume(String sessionId, int volume, long requestId) {
if (mConnectionReady) {
- mActiveConnection.setSessionVolume(sessionId, volume);
+ mActiveConnection.setSessionVolume(sessionId, volume, requestId);
updateBinding();
}
}
@@ -333,8 +333,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
return;
}
- if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
- Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_UNKNOWN");
+ if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
+ Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
return;
}
@@ -406,6 +406,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mCallback.onSessionReleased(this, sessionInfo);
}
+ private void onRequestFailed(Connection connection, long requestId, int reason) {
+ if (mActiveConnection != connection) {
+ return;
+ }
+
+ if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
+ Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE");
+ return;
+ }
+
+ mCallback.onRequestFailed(this, requestId, reason);
+ }
+
private void disconnect() {
if (mActiveConnection != null) {
mConnectionReady = false;
@@ -461,9 +474,9 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
}
- public void releaseSession(String sessionId) {
+ public void releaseSession(String sessionId, long requestId) {
try {
- mService.releaseSession(sessionId);
+ mService.releaseSession(sessionId, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "releaseSession: Failed to deliver request.");
}
@@ -477,41 +490,41 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
}
- public void selectRoute(String sessionId, String routeId) {
+ public void selectRoute(String sessionId, String routeId, long requestId) {
try {
- mService.selectRoute(sessionId, routeId);
+ mService.selectRoute(sessionId, routeId, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "selectRoute: Failed to deliver request.", ex);
}
}
- public void deselectRoute(String sessionId, String routeId) {
+ public void deselectRoute(String sessionId, String routeId, long requestId) {
try {
- mService.deselectRoute(sessionId, routeId);
+ mService.deselectRoute(sessionId, routeId, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "deselectRoute: Failed to deliver request.", ex);
}
}
- public void transferToRoute(String sessionId, String routeId) {
+ public void transferToRoute(String sessionId, String routeId, long requestId) {
try {
- mService.transferToRoute(sessionId, routeId);
+ mService.transferToRoute(sessionId, routeId, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "transferToRoute: Failed to deliver request.", ex);
}
}
- public void setRouteVolume(String routeId, int volume) {
+ public void setRouteVolume(String routeId, int volume, long requestId) {
try {
- mService.setRouteVolume(routeId, volume);
+ mService.setRouteVolume(routeId, volume, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "setRouteVolume: Failed to deliver request.", ex);
}
}
- public void setSessionVolume(String sessionId, int volume) {
+ public void setSessionVolume(String sessionId, int volume, long requestId) {
try {
- mService.setSessionVolume(sessionId, volume);
+ mService.setSessionVolume(sessionId, volume, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "setSessionVolume: Failed to deliver request.", ex);
}
@@ -541,6 +554,10 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
void postSessionReleased(RoutingSessionInfo sessionInfo) {
mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
}
+
+ void postSessionReleased(long requestId, int reason) {
+ mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
+ }
}
private static final class ServiceCallbackStub extends
@@ -594,5 +611,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
connection.postSessionReleased(sessionInfo);
}
}
+
+ @Override
+ public void notifyRequestFailed(long requestId, int reason) {
+ Connection connection = mConnectionRef.get();
+ if (connection != null) {
+ connection.postSessionReleased(requestId, reason);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 358891675912..e78a35cd88a4 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -30,7 +31,6 @@ import android.media.IMediaRouter2;
import android.media.IMediaRouter2Manager;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
-import android.media.MediaRoute2ProviderService;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.os.Binder;
@@ -70,6 +70,12 @@ class MediaRouter2ServiceImpl {
private static final String TAG = "MR2ServiceImpl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ /**
+ * TODO: Change this with the real request ID from MediaRouter2 when
+ * MediaRouter2 needs to get notified for the failures.
+ */
+ private static final long DUMMY_REQUEST_ID = -1;
+
private final Context mContext;
private final Object mLock = new Object();
final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
@@ -365,14 +371,14 @@ class MediaRouter2ServiceImpl {
}
public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int volume) {
+ MediaRoute2Info route, int volume, int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
Objects.requireNonNull(route, "route must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setRouteVolumeWithManagerLocked(manager, route, volume);
+ setRouteVolumeWithManagerLocked(manager, route, volume, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -397,7 +403,7 @@ class MediaRouter2ServiceImpl {
}
public void selectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route) {
+ MediaRoute2Info route, int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -407,7 +413,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- selectRouteWithManagerLocked(manager, uniqueSessionId, route);
+ selectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -415,7 +421,7 @@ class MediaRouter2ServiceImpl {
}
public void deselectRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route) {
+ MediaRoute2Info route, int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -425,7 +431,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- deselectRouteWithManagerLocked(manager, uniqueSessionId, route);
+ deselectRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -433,7 +439,7 @@ class MediaRouter2ServiceImpl {
}
public void transferToRouteWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
- MediaRoute2Info route) {
+ MediaRoute2Info route, int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -443,7 +449,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- transferToRouteWithManagerLocked(manager, uniqueSessionId, route);
+ transferToRouteWithManagerLocked(manager, uniqueSessionId, route, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -451,7 +457,7 @@ class MediaRouter2ServiceImpl {
}
public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
- String uniqueSessionId, int volume) {
+ String uniqueSessionId, int volume, int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -460,14 +466,15 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setSessionVolumeWithManagerLocked(manager, uniqueSessionId, volume);
+ setSessionVolumeWithManagerLocked(manager, uniqueSessionId, volume, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- public void releaseSessionWithManager(IMediaRouter2Manager manager, String uniqueSessionId) {
+ public void releaseSessionWithManager(IMediaRouter2Manager manager, String uniqueSessionId,
+ int requestId) {
Objects.requireNonNull(manager, "manager must not be null");
if (TextUtils.isEmpty(uniqueSessionId)) {
throw new IllegalArgumentException("uniqueSessionId must not be empty");
@@ -476,7 +483,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- releaseSessionWithManagerLocked(manager, uniqueSessionId);
+ releaseSessionWithManagerLocked(manager, uniqueSessionId, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -572,7 +579,7 @@ class MediaRouter2ServiceImpl {
obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
routerRecord.mUserRecord.mHandler, routerRecord));
routerRecord.mUserRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::updateDiscoveryPreference,
+ obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
routerRecord.mUserRecord.mHandler));
}
@@ -584,7 +591,7 @@ class MediaRouter2ServiceImpl {
if (routerRecord != null) {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
- routerRecord.mUserRecord.mHandler, route, volume));
+ routerRecord.mUserRecord.mHandler, route, volume, DUMMY_REQUEST_ID));
}
}
@@ -615,7 +622,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ DUMMY_REQUEST_ID));
}
private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -629,7 +637,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ DUMMY_REQUEST_ID));
}
private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -643,7 +652,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::transferToRouteOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ DUMMY_REQUEST_ID));
}
private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -657,7 +667,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
- routerRecord.mUserRecord.mHandler, uniqueSessionId, volume));
+ routerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
+ DUMMY_REQUEST_ID));
}
private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -671,7 +682,8 @@ class MediaRouter2ServiceImpl {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
- routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId));
+ routerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
+ DUMMY_REQUEST_ID));
}
////////////////////////////////////////////////////////////
@@ -744,16 +756,18 @@ class MediaRouter2ServiceImpl {
}
private void setRouteVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull MediaRoute2Info route, int volume) {
+ @NonNull MediaRoute2Info route, int volume, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
if (managerRecord == null) {
return;
}
+
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setRouteVolumeOnHandler,
- managerRecord.mUserRecord.mHandler, route, volume));
+ managerRecord.mUserRecord.mHandler, route, volume, uniqueRequestId));
}
private void requestCreateSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
@@ -778,7 +792,7 @@ class MediaRouter2ServiceImpl {
}
private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -790,13 +804,15 @@ class MediaRouter2ServiceImpl {
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterforSessionLocked(uniqueSessionId);
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::selectRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ uniqueRequestId));
}
private void deselectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -808,13 +824,15 @@ class MediaRouter2ServiceImpl {
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterforSessionLocked(uniqueSessionId);
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::deselectRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ uniqueRequestId));
}
private void transferToRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -826,13 +844,15 @@ class MediaRouter2ServiceImpl {
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterforSessionLocked(uniqueSessionId);
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::transferToRouteOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route));
+ managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId, route,
+ uniqueRequestId));
}
private void setSessionVolumeWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId, int volume) {
+ @NonNull String uniqueSessionId, int volume, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -840,13 +860,15 @@ class MediaRouter2ServiceImpl {
return;
}
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::setSessionVolumeOnHandler,
- managerRecord.mUserRecord.mHandler, uniqueSessionId, volume));
+ managerRecord.mUserRecord.mHandler, uniqueSessionId, volume,
+ uniqueRequestId));
}
private void releaseSessionWithManagerLocked(@NonNull IMediaRouter2Manager manager,
- @NonNull String uniqueSessionId) {
+ @NonNull String uniqueSessionId, int requestId) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -856,10 +878,15 @@ class MediaRouter2ServiceImpl {
RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
.findRouterforSessionLocked(uniqueSessionId);
+ if (routerRecord == null) {
+ return;
+ }
+ long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
managerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::releaseSessionOnHandler,
- managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId));
+ managerRecord.mUserRecord.mHandler, routerRecord, uniqueSessionId,
+ uniqueRequestId));
}
////////////////////////////////////////////////////////////
@@ -1100,6 +1127,13 @@ class MediaRouter2ServiceImpl {
this, provider, sessionInfo));
}
+ @Override
+ public void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId,
+ int reason) {
+ sendMessage(PooledLambda.obtainMessage(UserHandler::onRequestFailedOnHandler,
+ this, provider, requestId, reason));
+ }
+
@Nullable
public RouterRecord findRouterforSessionLocked(@NonNull String uniqueSessionId) {
return mSessionToRouterMap.get(uniqueSessionId);
@@ -1195,7 +1229,7 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
Slog.w(TAG, "Ignoring session creation request since no provider found for"
+ " given route=" + route);
- notifySessionCreationFailed(routerRecord, toOriginalRequestId(requestId));
+ notifySessionCreationFailedToRouter(routerRecord, toOriginalRequestId(requestId));
return;
}
@@ -1210,7 +1244,7 @@ class MediaRouter2ServiceImpl {
// routerRecord can be null if the session is system's.
private void selectRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"selecting")) {
return;
@@ -1222,12 +1256,12 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+ provider.selectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(), requestId);
}
// routerRecord can be null if the session is system's.
private void deselectRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"deselecting")) {
return;
@@ -1239,12 +1273,13 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+ provider.deselectRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
+ requestId);
}
// routerRecord can be null if the session is system's.
private void transferToRouteOnHandler(@Nullable RouterRecord routerRecord,
- @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
+ @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, long requestId) {
if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
"transferring to")) {
return;
@@ -1256,7 +1291,8 @@ class MediaRouter2ServiceImpl {
if (provider == null) {
return;
}
- provider.transferToRoute(getOriginalId(uniqueSessionId), route.getOriginalId());
+ provider.transferToRoute(getOriginalId(uniqueSessionId), route.getOriginalId(),
+ requestId);
}
private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
@@ -1299,7 +1335,7 @@ class MediaRouter2ServiceImpl {
}
private void releaseSessionOnHandler(@NonNull RouterRecord routerRecord,
- @NonNull String uniqueSessionId) {
+ @NonNull String uniqueSessionId, long uniqueRequestId) {
final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
if (matchingRecord != routerRecord) {
Slog.w(TAG, "Ignoring releasing session from non-matching router."
@@ -1329,14 +1365,14 @@ class MediaRouter2ServiceImpl {
return;
}
- provider.releaseSession(sessionId);
+ provider.releaseSession(sessionId, uniqueRequestId);
}
private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo, long requestId) {
notifySessionCreatedToManagers(getManagers(), sessionInfo);
- if (requestId == MediaRoute2ProviderService.REQUEST_ID_UNKNOWN) {
+ if (requestId == REQUEST_ID_NONE) {
// The session is created without any matching request.
return;
}
@@ -1362,7 +1398,7 @@ class MediaRouter2ServiceImpl {
if (sessionInfo == null) {
// Failed
- notifySessionCreationFailed(matchingRequest.mRouterRecord,
+ notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
toOriginalRequestId(requestId));
return;
}
@@ -1374,13 +1410,13 @@ class MediaRouter2ServiceImpl {
Slog.w(TAG, "Created session doesn't match the original request."
+ " originalRouteId=" + originalRouteId
+ ", requestId=" + requestId + ", sessionInfo=" + sessionInfo);
- notifySessionCreationFailed(matchingRequest.mRouterRecord,
+ notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
toOriginalRequestId(requestId));
return;
}
// Succeeded
- notifySessionCreated(matchingRequest.mRouterRecord,
+ notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
sessionInfo, toOriginalRequestId(requestId));
mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
}
@@ -1405,7 +1441,7 @@ class MediaRouter2ServiceImpl {
}
mSessionCreationRequests.remove(matchingRequest);
- notifySessionCreationFailed(matchingRequest.mRouterRecord,
+ notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
toOriginalRequestId(requestId));
}
@@ -1429,7 +1465,7 @@ class MediaRouter2ServiceImpl {
Slog.w(TAG, "No matching router found for session=" + sessionInfo);
return;
}
- notifySessionInfoChanged(routerRecord, sessionInfo);
+ notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
}
private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@@ -1442,10 +1478,38 @@ class MediaRouter2ServiceImpl {
Slog.w(TAG, "No matching router found for session=" + sessionInfo);
return;
}
- notifySessionReleased(routerRecord, sessionInfo);
+ notifySessionReleasedToRouter(routerRecord, sessionInfo);
}
- private void notifySessionCreated(@NonNull RouterRecord routerRecord,
+ private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
+ long requestId, int reason) {
+ final int managerId = toRouterOrManagerId(requestId);
+
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return;
+ }
+
+ ManagerRecord managerToNotifyFailure = null;
+ synchronized (service.mLock) {
+ for (ManagerRecord manager : mUserRecord.mManagerRecords) {
+ if (manager.mManagerId == managerId) {
+ managerToNotifyFailure = manager;
+ break;
+ }
+ }
+ }
+
+ if (managerToNotifyFailure == null) {
+ Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
+ return;
+ }
+
+ notifyRequestFailedToManager(
+ managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+ }
+
+ private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
@NonNull RoutingSessionInfo sessionInfo, int requestId) {
try {
routerRecord.mRouter.notifySessionCreated(sessionInfo, requestId);
@@ -1455,7 +1519,7 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifySessionCreationFailed(@NonNull RouterRecord routerRecord,
+ private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
int requestId) {
try {
routerRecord.mRouter.notifySessionCreated(/* sessionInfo= */ null, requestId);
@@ -1465,7 +1529,7 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifySessionInfoChanged(@NonNull RouterRecord routerRecord,
+ private void notifySessionInfoChangedToRouter(@NonNull RouterRecord routerRecord,
@NonNull RoutingSessionInfo sessionInfo) {
try {
routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
@@ -1475,7 +1539,7 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifySessionReleased(@NonNull RouterRecord routerRecord,
+ private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
@NonNull RoutingSessionInfo sessionInfo) {
try {
routerRecord.mRouter.notifySessionReleased(sessionInfo);
@@ -1485,21 +1549,23 @@ class MediaRouter2ServiceImpl {
}
}
- private void setRouteVolumeOnHandler(@NonNull MediaRoute2Info route, int volume) {
+ private void setRouteVolumeOnHandler(@NonNull MediaRoute2Info route, int volume,
+ long requestId) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
- provider.setRouteVolume(route.getOriginalId(), volume);
+ provider.setRouteVolume(route.getOriginalId(), volume, requestId);
}
}
- private void setSessionVolumeOnHandler(@NonNull String uniqueSessionId, int volume) {
+ private void setSessionVolumeOnHandler(@NonNull String uniqueSessionId, int volume,
+ long requestId) {
final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
if (provider == null) {
Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
+ "id=" + uniqueSessionId);
return;
}
- provider.setSessionVolume(getOriginalId(uniqueSessionId), volume);
+ provider.setSessionVolume(getOriginalId(uniqueSessionId), volume, requestId);
}
private List<IMediaRouter2> getRouters() {
@@ -1683,7 +1749,17 @@ class MediaRouter2ServiceImpl {
}
}
- private void updateDiscoveryPreference() {
+ private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
+ int requestId, int reason) {
+ try {
+ manager.notifyRequestFailed(requestId, reason);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify manager of the request failure."
+ + " Manager probably died.", ex);
+ }
+ }
+
+ private void updateDiscoveryPreferenceOnHandler() {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
return;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 580fc5250e35..a13ee1058a26 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -543,8 +543,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
public void setRouteVolumeWithManager(IMediaRouter2Manager manager,
- MediaRoute2Info route, int volume) {
- mService2.setRouteVolumeWithManager(manager, route, volume);
+ MediaRoute2Info route, int volume, int requestId) {
+ mService2.setRouteVolumeWithManager(manager, route, volume, requestId);
}
// Binder call
@@ -557,35 +557,36 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
public void selectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route) {
- mService2.selectRouteWithManager(manager, sessionId, route);
+ MediaRoute2Info route, int requestId) {
+ mService2.selectRouteWithManager(manager, sessionId, route, requestId);
}
// Binder call
@Override
public void deselectRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route) {
- mService2.deselectRouteWithManager(manager, sessionId, route);
+ MediaRoute2Info route, int requestId) {
+ mService2.deselectRouteWithManager(manager, sessionId, route, requestId);
}
// Binder call
@Override
public void transferToRouteWithManager(IMediaRouter2Manager manager, String sessionId,
- MediaRoute2Info route) {
- mService2.transferToRouteWithManager(manager, sessionId, route);
+ MediaRoute2Info route, int requestId) {
+ mService2.transferToRouteWithManager(manager, sessionId, route, requestId);
}
// Binder call
@Override
public void setSessionVolumeWithManager(IMediaRouter2Manager manager,
- String sessionId, int volume) {
- mService2.setSessionVolumeWithManager(manager, sessionId, volume);
+ String sessionId, int volume, int requestId) {
+ mService2.setSessionVolumeWithManager(manager, sessionId, volume, requestId);
}
// Binder call
@Override
- public void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId) {
- mService2.releaseSessionWithManager(manager, sessionId);
+ public void releaseSessionWithManager(IMediaRouter2Manager manager, String sessionId,
+ int requestId) {
+ mService2.releaseSessionWithManager(manager, sessionId, requestId);
}
void restoreBluetoothA2dp() {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index f7e1398a2bd3..da9c27e5bf0a 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -18,6 +18,7 @@ package com.android.server.media;
import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
+import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -130,26 +131,27 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void releaseSession(String sessionId) {
+ public void releaseSession(String sessionId, long requestId) {
// Do nothing
}
+
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
// Do nothing
}
@Override
- public void selectRoute(String sessionId, String routeId) {
+ public void selectRoute(String sessionId, String routeId, long requestId) {
// Do nothing since we don't support multiple BT yet.
}
@Override
- public void deselectRoute(String sessionId, String routeId) {
+ public void deselectRoute(String sessionId, String routeId, long requestId) {
// Do nothing since we don't support multiple BT yet.
}
@Override
- public void transferToRoute(String sessionId, String routeId) {
+ public void transferToRoute(String sessionId, String routeId, long requestId) {
if (TextUtils.equals(routeId, mDefaultRoute.getId())) {
mBtRouteProvider.transferTo(null);
} else {
@@ -158,7 +160,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void setRouteVolume(String routeId, int volume) {
+ public void setRouteVolume(String routeId, int volume, long requestId) {
if (!TextUtils.equals(routeId, mSelectedRouteId)) {
return;
}
@@ -166,7 +168,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
- public void setSessionVolume(String sessionId, int volume) {
+ public void setSessionVolume(String sessionId, int volume, long requestId) {
// Do nothing since we don't support grouping volume yet.
}
@@ -192,6 +194,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
+ //TODO: Guess the exact type using AudioDevice
+ .setType(TYPE_BUILTIN_SPEAKER)
.addFeature(FEATURE_LIVE_AUDIO)
.addFeature(FEATURE_LIVE_VIDEO)
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index fce10e62bc5d..c301cd2339ec 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -27,4 +27,6 @@ public interface NotificationManagerInternal {
String tag, int id, int userId);
void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId);
+
+ void onConversationRemoved(String pkg, int uid, String conversationId);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0d402e57d335..475f229562dd 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -772,7 +772,7 @@ public class NotificationManagerService extends SystemService {
parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
- mSnoozeHelper.readXml(parser);
+ mSnoozeHelper.readXml(parser, System.currentTimeMillis());
}
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
if (forRestore && userId != UserHandle.USER_SYSTEM) {
@@ -2322,6 +2322,8 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onBootPhaseAppsCanStart();
mHistoryManager.onBootPhaseAppsCanStart();
registerDeviceConfigChange();
+ } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
}
}
@@ -5474,6 +5476,11 @@ public class NotificationManagerService extends SystemService {
});
}
+ @Override
+ public void onConversationRemoved(String pkg, int uid, String conversationId) {
+ onConversationRemovedInternal(pkg, uid, conversationId);
+ }
+
@GuardedBy("mNotificationLock")
private void removeForegroundServiceFlagLocked(NotificationRecord r) {
if (r == null) {
@@ -5676,7 +5683,7 @@ public class NotificationManagerService extends SystemService {
mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
}
- public void onConversationRemoved(String pkg, int uid, String conversationId) {
+ private void onConversationRemovedInternal(String pkg, int uid, String conversationId) {
checkCallerIsSystem();
Preconditions.checkStringNotEmpty(pkg);
Preconditions.checkStringNotEmpty(conversationId);
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index bae1dd3c6cb6..d60c29119c18 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -36,6 +36,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -43,9 +44,7 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
-import java.sql.Array;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -172,7 +171,7 @@ public class SnoozeHelper {
for (int i = 0; i < allRecords.size(); i++) {
NotificationRecord r = allRecords.valueAt(i);
String currentGroupKey = r.getSbn().getGroup();
- if (currentGroupKey.equals(groupKey)) {
+ if (Objects.equals(currentGroupKey, groupKey)) {
records.add(r);
}
}
@@ -217,7 +216,7 @@ public class SnoozeHelper {
snooze(record);
scheduleRepost(pkg, key, userId, duration);
- Long activateAt = System.currentTimeMillis() + duration;
+ Long activateAt = SystemClock.elapsedRealtime() + duration;
synchronized (mPersistedSnoozedNotifications) {
storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
}
@@ -244,8 +243,6 @@ public class SnoozeHelper {
}
storeRecord(record.getSbn().getPackageName(), record.getKey(),
userId, mSnoozedNotifications, record);
- mPackages.put(record.getKey(), record.getSbn().getPackageName());
- mUsers.put(record.getKey(), userId);
}
private <T> void storeRecord(String pkg, String key, Integer userId,
@@ -258,6 +255,8 @@ public class SnoozeHelper {
keyToValue.put(key, object);
targets.put(getPkgKey(userId, pkg), keyToValue);
+ mPackages.put(key, pkg);
+ mUsers.put(key, userId);
}
private <T> T removeRecord(String pkg, String key, Integer userId,
@@ -425,12 +424,34 @@ public class SnoozeHelper {
PendingIntent.FLAG_UPDATE_CURRENT);
}
+ public void scheduleRepostsForPersistedNotifications(long currentTime) {
+ for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) {
+ for (int i = 0; i < snoozed.size(); i++) {
+ String key = snoozed.keyAt(i);
+ Long time = snoozed.valueAt(i);
+ String pkg = mPackages.get(key);
+ Integer userId = mUsers.get(key);
+ if (time == null || pkg == null || userId == null) {
+ Slog.w(TAG, "data out of sync: " + time + "|" + pkg + "|" + userId);
+ continue;
+ }
+ if (time != null && time > currentTime) {
+ scheduleRepostAtTime(pkg, key, userId, time);
+ }
+ }
+
+ }
+ }
+
private void scheduleRepost(String pkg, String key, int userId, long duration) {
+ scheduleRepostAtTime(pkg, key, userId, SystemClock.elapsedRealtime() + duration);
+ }
+
+ private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
long identity = Binder.clearCallingIdentity();
try {
final PendingIntent pi = createPendingIntent(pkg, key, userId);
mAm.cancel(pi);
- long time = SystemClock.elapsedRealtime() + duration;
if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
} finally {
@@ -496,6 +517,7 @@ public class SnoozeHelper {
private interface Inserter<T> {
void insert(T t) throws IOException;
}
+
private <T> void writeXml(XmlSerializer out,
ArrayMap<String, ArrayMap<String, T>> targets, String tag,
Inserter<T> attributeInserter)
@@ -503,12 +525,13 @@ public class SnoozeHelper {
synchronized (targets) {
final int M = targets.size();
for (int i = 0; i < M; i++) {
- String userIdPkgKey = targets.keyAt(i);
// T is a String (snoozed until context) or Long (snoozed until time)
ArrayMap<String, T> keyToValue = targets.valueAt(i);
for (int j = 0; j < keyToValue.size(); j++) {
String key = keyToValue.keyAt(j);
T value = keyToValue.valueAt(j);
+ String pkg = mPackages.get(key);
+ Integer userId = mUsers.get(key);
out.startTag(null, tag);
@@ -518,8 +541,7 @@ public class SnoozeHelper {
XML_SNOOZED_NOTIFICATION_VERSION);
out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
- String pkg = mPackages.get(key);
- int userId = mUsers.get(key);
+
out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
String.valueOf(userId));
@@ -530,7 +552,7 @@ public class SnoozeHelper {
}
}
- protected void readXml(XmlPullParser parser)
+ protected void readXml(XmlPullParser parser, long currentTime)
throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -547,16 +569,15 @@ public class SnoozeHelper {
try {
final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
- final int userId = Integer.parseInt(
- parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_USER_ID));
+ final int userId = XmlUtils.readIntAttribute(
+ parser, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
- final Long time = Long.parseLong(
- parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_TIME));
- if (time > System.currentTimeMillis()) { //only read new stuff
+ final Long time = XmlUtils.readLongAttribute(
+ parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
+ if (time > currentTime) { //only read new stuff
synchronized (mPersistedSnoozedNotifications) {
storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time);
}
- scheduleRepost(pkg, key, userId, time - System.currentTimeMillis());
}
}
if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 8ad3e9df8bdf..f37af3aef657 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -234,11 +234,11 @@ public class Installer extends SystemService {
}
public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
- String dataAppName, int appId, String seInfo, int targetSdkVersion,
+ int appId, String seInfo, int targetSdkVersion,
String fromCodePath) throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
+ mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo,
targetSdkVersion, fromCodePath);
} catch (Exception e) {
throw InstallerException.from(e);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 261caba98e4f..8031eaa62084 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -72,6 +72,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -134,6 +135,8 @@ public class LauncherAppsService extends SystemService {
private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+ private final ShortcutChangeHandler mShortcutChangeHandler;
+
private final Handler mCallbackHandler;
private PackageInstallerService mPackageInstallerService;
@@ -153,6 +156,8 @@ public class LauncherAppsService extends SystemService {
mShortcutServiceInternal = Objects.requireNonNull(
LocalServices.getService(ShortcutServiceInternal.class));
mShortcutServiceInternal.addListener(mPackageMonitor);
+ mShortcutChangeHandler = new ShortcutChangeHandler(mUserManagerInternal);
+ mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler);
mCallbackHandler = BackgroundThread.getHandler();
mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
}
@@ -720,12 +725,37 @@ public class LauncherAppsService extends SystemService {
@Override
public void registerShortcutChangeCallback(String callingPackage, long changedSince,
String packageName, List shortcutIds, List<LocusId> locusIds,
- ComponentName componentName, int flags, IShortcutChangeCallback callback,
- int callbackId) {
+ ComponentName componentName, int flags, IShortcutChangeCallback callback) {
+ ensureShortcutPermission(callingPackage);
+
+ if (shortcutIds != null && packageName == null) {
+ throw new IllegalArgumentException(
+ "To query by shortcut ID, package name must also be set");
+ }
+ if (locusIds != null && packageName == null) {
+ throw new IllegalArgumentException(
+ "To query by locus ID, package name must also be set");
+ }
+
+ UserHandle user = UserHandle.of(injectCallingUserId());
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_GRANTED) {
+ user = null;
+ }
+
+ // TODO: When ShortcutQueryWrapper (ag/10323729) is available, pass that directly.
+ ShortcutChangeHandler.QueryInfo query = new ShortcutChangeHandler.QueryInfo(
+ changedSince, packageName, shortcutIds, locusIds, componentName, flags, user);
+ mShortcutChangeHandler.addShortcutChangeCallback(callback, query);
}
@Override
- public void unregisterShortcutChangeCallback(String callingPackage, int callbackId) {
+ public void unregisterShortcutChangeCallback(String callingPackage,
+ IShortcutChangeCallback callback) {
+ ensureShortcutPermission(callingPackage);
+
+ mShortcutChangeHandler.removeShortcutChangeCallback(callback);
}
@Override
@@ -1005,6 +1035,153 @@ public class LauncherAppsService extends SystemService {
mCallbackHandler.post(r);
}
+ public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback {
+
+ static class QueryInfo {
+ final long mChangedSince;
+ final String mPackage;
+ final List<String> mShortcutIds;
+ final List<LocusId> mLocusIds;
+ final ComponentName mActivity;
+ final int mQueryFlags;
+ final UserHandle mCallbackUser;
+
+ QueryInfo(long changedSince, String packageName, List<String> shortcutIds,
+ List<LocusId> locusIds, ComponentName activity, int flags,
+ UserHandle callbackUser) {
+ mChangedSince = changedSince;
+ mPackage = packageName;
+ mShortcutIds = shortcutIds;
+ mLocusIds = locusIds;
+ mActivity = activity;
+ mQueryFlags = flags;
+ mCallbackUser = callbackUser;
+ }
+ }
+
+ private final UserManagerInternal mUserManagerInternal;
+
+ ShortcutChangeHandler(UserManagerInternal userManager) {
+ mUserManagerInternal = userManager;
+ }
+
+ private final RemoteCallbackList<IShortcutChangeCallback> mCallbacks =
+ new RemoteCallbackList<>();
+
+ public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback,
+ QueryInfo query) {
+ mCallbacks.unregister(callback);
+ mCallbacks.register(callback, query);
+ }
+
+ public synchronized void removeShortcutChangeCallback(
+ IShortcutChangeCallback callback) {
+ mCallbacks.unregister(callback);
+ }
+
+ @Override
+ public void onShortcutsAddedOrUpdated(String packageName, List<ShortcutInfo> shortcuts,
+ UserHandle user) {
+ onShortcutEvent(packageName, shortcuts, user, false);
+ }
+
+ @Override
+ public void onShortcutsRemoved(String packageName, List<ShortcutInfo> shortcuts,
+ UserHandle user) {
+ onShortcutEvent(packageName, shortcuts, user, true);
+ }
+
+ private void onShortcutEvent(String packageName,
+ List<ShortcutInfo> shortcuts, UserHandle user, boolean shortcutsRemoved) {
+ int count = mCallbacks.beginBroadcast();
+
+ for (int i = 0; i < count; i++) {
+ final IShortcutChangeCallback callback = mCallbacks.getBroadcastItem(i);
+ final QueryInfo query = (QueryInfo) mCallbacks.getBroadcastCookie(i);
+
+ if (query.mCallbackUser != null && !hasUserAccess(query.mCallbackUser, user)) {
+ // Callback owner does not have access to the shortcuts' user.
+ continue;
+ }
+
+ // Filter the list by query, if any matches exists, send via callback.
+ List<ShortcutInfo> matchedList =
+ filterShortcutsByQuery(packageName, shortcuts, query);
+ if (!CollectionUtils.isEmpty(matchedList)) {
+ try {
+ if (shortcutsRemoved) {
+ callback.onShortcutsRemoved(packageName, matchedList, user);
+ } else {
+ callback.onShortcutsAddedOrUpdated(packageName, matchedList, user);
+ }
+ } catch (RemoteException e) {
+ // The RemoteCallbackList will take care of removing the dead object.
+ }
+ }
+ }
+
+ mCallbacks.finishBroadcast();
+ }
+
+ public static List<ShortcutInfo> filterShortcutsByQuery(String packageName,
+ List<ShortcutInfo> shortcuts, QueryInfo query) {
+ if (query.mPackage != null && query.mPackage != packageName) {
+ return null;
+ }
+
+ List<ShortcutInfo> matches = new ArrayList<>();
+
+ final boolean matchDynamic =
+ (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
+ final boolean matchPinned =
+ (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
+ final boolean matchManifest =
+ (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
+ final boolean matchCached =
+ (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_CACHED) != 0;
+ final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
+ | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
+ | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
+ | (matchCached ? ShortcutInfo.FLAG_CACHED : 0);
+
+ for (int i = 0; i < shortcuts.size(); i++) {
+ final ShortcutInfo si = shortcuts.get(i);
+
+ if (query.mActivity != null && !query.mActivity.equals(si.getActivity())) {
+ continue;
+ }
+
+ if (query.mChangedSince != 0
+ && query.mChangedSince > si.getLastChangedTimestamp()) {
+ continue;
+ }
+
+ if (query.mShortcutIds != null && !query.mShortcutIds.contains(si.getId())) {
+ continue;
+ }
+
+ if (query.mLocusIds != null && !query.mLocusIds.contains(si.getLocusId())) {
+ continue;
+ }
+
+ if ((shortcutFlags & si.getFlags()) != 0) {
+ matches.add(si);
+ }
+ }
+
+ return matches;
+ }
+
+ private boolean hasUserAccess(UserHandle callbackUser, UserHandle shortcutUser) {
+ final int callbackUserId = callbackUser.getIdentifier();
+ final int shortcutUserId = shortcutUser.getIdentifier();
+
+ if (shortcutUser == callbackUser) return true;
+ return mUserManagerInternal.isProfileAccessible(callbackUserId, shortcutUserId,
+ null, false);
+ }
+ }
+
private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
// TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 92507e5a0e25..52052f8dd871 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12760,7 +12760,11 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
+ userId);
}
- Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ if (restrictionFlags != 0 && !isSuspendAllowedForUser(userId)) {
+ Slog.w(TAG, "Cannot restrict packages due to restrictions on user " + userId);
+ return packageNames;
+ }
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
@@ -12847,6 +12851,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
+ if (suspended && !isSuspendAllowedForUser(userId)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ return packageNames;
+ }
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
@@ -12985,30 +12993,41 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ void unsuspendForSuspendingPackage(String suspendingPackage, int userId) {
+ final String[] allPackages;
+ synchronized (mLock) {
+ allPackages = mPackages.keySet().toArray(new String[mPackages.size()]);
+ }
+ removeSuspensionsBySuspendingPackage(allPackages, suspendingPackage::equals, userId);
+ }
+
/**
- * Immediately unsuspends any packages suspended by the given package. To be called
- * when such a package's data is cleared or it is removed from the device.
+ * Removes any suspensions on given packages that were added by packages that pass the given
+ * predicate.
*
- * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
- * synchronously
+ * <p> Caller must flush package restrictions if it cares about immediate data consistency.
*
- * @param suspendingPackage The suspending package
+ * @param packagesToChange The packages on which the suspension are to be removed.
+ * @param suspendingPackagePredicate A predicate identifying the suspending packages whose
+ * suspensions will be removed.
* @param userId The user for which the changes are taking place.
*/
- private void unsuspendForSuspendingPackage(String suspendingPackage, int userId) {
+ void removeSuspensionsBySuspendingPackage(String[] packagesToChange,
+ Predicate<String> suspendingPackagePredicate, int userId) {
final List<String> unsuspendedPackages = new ArrayList<>();
final IntArray unsuspendedUids = new IntArray();
synchronized (mLock) {
- for (PackageSetting ps : mSettings.mPackages.values()) {
- final PackageUserState pus = ps.readUserState(userId);
- if (pus.suspended) {
- ps.removeSuspension(suspendingPackage, userId);
+ for (String packageName : packagesToChange) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps.getSuspended(userId)) {
+ ps.removeSuspension(suspendingPackagePredicate, userId);
if (!ps.getSuspended(userId)) {
unsuspendedPackages.add(ps.name);
unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId()));
}
}
}
+ scheduleWritePackageRestrictionsLocked(userId);
}
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
@@ -13016,13 +13035,67 @@ public class PackageManagerService extends IPackageManager.Stub
sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
sendPackagesSuspendedForUser(packageArray, unsuspendedUids.toArray(), userId, false);
}
- // Write package restrictions immediately to avoid an inconsistent state.
- mSettings.writePackageRestrictionsLPr(userId);
+ }
+
+ void removeAllDistractingPackageRestrictions(int userId) {
+ final String[] allPackages;
+ synchronized (mLock) {
+ allPackages = mPackages.keySet().toArray(new String[mPackages.size()]);
+ }
+ PackageManagerService.this.removeDistractingPackageRestrictions(allPackages, userId);
+ }
+
+ /**
+ * Removes any {@link android.content.pm.PackageManager.DistractionRestriction restrictions}
+ * set on given packages.
+ *
+ * <p> Caller must flush package restrictions if it cares about immediate data consistency.
+ *
+ * @param packagesToChange The packages on which restrictions are to be removed.
+ * @param userId the user for which changes are taking place.
+ */
+ void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) {
+ final List<String> changedPackages = new ArrayList<>();
+ final IntArray changedUids = new IntArray();
+ synchronized (mLock) {
+ for (String packageName : packagesToChange) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps.getDistractionFlags(userId) != 0) {
+ ps.setDistractionFlags(0, userId);
+ changedPackages.add(ps.name);
+ changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+ }
+ }
+ if (!changedPackages.isEmpty()) {
+ final String[] packageArray = changedPackages.toArray(
+ new String[changedPackages.size()]);
+ sendDistractingPackagesChanged(packageArray, changedUids.toArray(), userId, 0);
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
+ }
+ }
+
+ private boolean isCallerDeviceOrProfileOwner(int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SYSTEM_UID) {
+ return true;
+ }
+ final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ if (ownerPackage != null) {
+ return callingUid == getPackageUidInternal(ownerPackage, 0, userId, callingUid);
+ }
+ return false;
+ }
+
+ private boolean isSuspendAllowedForUser(int userId) {
+ return isCallerDeviceOrProfileOwner(userId)
+ || (!mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)
+ && !mUserManager.hasUserRestriction(UserManager.DISALLOW_UNINSTALL_APPS, userId));
}
@Override
public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
- Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"getUnsuspendablePackagesForUser");
final int callingUid = Binder.getCallingUid();
@@ -13030,11 +13103,23 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Calling uid " + callingUid
+ " cannot query getUnsuspendablePackagesForUser for user " + userId);
}
+ if (!isSuspendAllowedForUser(userId)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ return packageNames;
+ }
final ArraySet<String> unactionablePackages = new ArraySet<>();
final boolean[] canSuspend = canSuspendPackageForUserInternal(packageNames, userId);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
unactionablePackages.add(packageNames[i]);
+ continue;
+ }
+ synchronized (mLock) {
+ final PackageSetting ps = mSettings.mPackages.get(packageNames[i]);
+ if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
+ unactionablePackages.add(packageNames[i]);
+ }
}
}
return unactionablePackages.toArray(new String[unactionablePackages.size()]);
@@ -13051,6 +13136,7 @@ public class PackageManagerService extends IPackageManager.Stub
@NonNull
private boolean[] canSuspendPackageForUserInternal(@NonNull String[] packageNames, int userId) {
final boolean[] canSuspend = new boolean[packageNames.length];
+ final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
final long callingId = Binder.clearCallingIdentity();
try {
final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
@@ -13100,6 +13186,11 @@ public class PackageManagerService extends IPackageManager.Stub
+ "\": protected package");
continue;
}
+ if (!isCallerOwner && mSettings.getBlockUninstallLPr(userId, packageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": blocked by admin");
+ continue;
+ }
// Cannot suspend static shared libs as they are considered
// a part of the using app (emulating static linking). Also
@@ -13991,20 +14082,18 @@ public class PackageManagerService extends IPackageManager.Stub
final String fromUuid;
final String toUuid;
final String packageName;
- final String dataAppName;
final int appId;
final String seinfo;
final int targetSdkVersion;
final String fromCodePath;
public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
- String dataAppName, int appId, String seinfo, int targetSdkVersion,
+ int appId, String seinfo, int targetSdkVersion,
String fromCodePath) {
this.moveId = moveId;
this.fromUuid = fromUuid;
this.toUuid = toUuid;
this.packageName = packageName;
- this.dataAppName = dataAppName;
this.appId = appId;
this.seinfo = seinfo;
this.targetSdkVersion = targetSdkVersion;
@@ -15120,7 +15209,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mInstaller) {
try {
mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
- move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion,
+ move.appId, move.seinfo, move.targetSdkVersion,
move.fromCodePath);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to move app", e);
@@ -15128,7 +15217,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- codeFile = new File(Environment.getDataAppDirectory(move.toUuid), move.dataAppName);
+ final String toPathName = new File(move.fromCodePath).getName();
+ codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
resourceFile = codeFile;
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
@@ -15172,8 +15262,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
private boolean cleanUp(String volumeUuid) {
+ final String toPathName = new File(move.fromCodePath).getName();
final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
- move.dataAppName);
+ toPathName);
Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
final int[] userIds = mUserManager.getUserIds();
synchronized (mInstallLock) {
@@ -18449,6 +18540,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
== PERMISSION_GRANTED) {
unsuspendForSuspendingPackage(packageName, userId);
+ removeAllDistractingPackageRestrictions(userId);
+ flushPackageRestrictionsAsUserInternalLocked(userId);
}
}
} else {
@@ -19972,6 +20065,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
pkgSetting.setEnabled(newState, userId, callingPackage);
+ if (newState == COMPONENT_ENABLED_STATE_DISABLED_USER
+ || newState == COMPONENT_ENABLED_STATE_DISABLED
+ && pkgSetting.getPermissionsState().hasPermission(
+ Manifest.permission.SUSPEND_APPS, userId)) {
+ // This app should not generally be allowed to get disabled by the UI, but if it
+ // ever does, we don't want to end up with some of the user's apps permanently
+ // blocked
+ unsuspendForSuspendingPackage(packageName, userId);
+ removeAllDistractingPackageRestrictions(userId);
+ }
}
} else {
synchronized (mLock) {
@@ -22113,7 +22216,11 @@ public class PackageManagerService extends IPackageManager.Stub
targetSdkVersion = pkg.getTargetSdkVersion();
freezer = freezePackage(packageName, "movePackageInternal");
installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
- fromCodePath = pkg.getCodePath();
+ if (codeFile.getParentFile().getName().startsWith(RANDOM_DIR_PREFIX)) {
+ fromCodePath = codeFile.getParentFile().getAbsolutePath();
+ } else {
+ fromCodePath = codeFile.getAbsolutePath();
+ }
}
final Bundle extras = new Bundle();
@@ -22240,9 +22347,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}).start();
- final String dataAppName = codeFile.getName();
move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
- dataAppName, appId, seinfo, targetSdkVersion, fromCodePath);
+ appId, seinfo, targetSdkVersion, fromCodePath);
} else {
move = null;
}
@@ -23210,6 +23316,43 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public void removeAllNonSystemPackageSuspensions(int userId) {
+ final String[] allPackages;
+ synchronized (mLock) {
+ allPackages = mPackages.keySet().toArray(new String[mPackages.size()]);
+ }
+ PackageManagerService.this.removeSuspensionsBySuspendingPackage(allPackages,
+ (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ userId);
+ }
+
+ @Override
+ public void removeNonSystemPackageSuspensions(String packageName, int userId) {
+ PackageManagerService.this.removeSuspensionsBySuspendingPackage(
+ new String[]{packageName},
+ (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ userId);
+ }
+
+ @Override
+ public void flushPackageRestrictions(int userId) {
+ synchronized (mLock) {
+ PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId);
+ }
+ }
+
+ @Override
+ public void removeDistractingPackageRestrictions(String packageName, int userId) {
+ PackageManagerService.this.removeDistractingPackageRestrictions(
+ new String[]{packageName}, userId);
+ }
+
+ @Override
+ public void removeAllDistractingPackageRestrictions(int userId) {
+ PackageManagerService.this.removeAllDistractingPackageRestrictions(userId);
+ }
+
+ @Override
public String getSuspendingPackage(String suspendedPackage, int userId) {
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 18bc879b978b..318a233b6e14 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -43,6 +43,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Predicate;
/**
* Settings base class for pending and resolved classes.
@@ -433,6 +434,22 @@ public abstract class PackageSettingBase extends SettingBase {
existingUserState.suspended = (existingUserState.suspendParams != null);
}
+ void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
+ final PackageUserState existingUserState = modifyUserState(userId);
+ if (existingUserState.suspendParams != null) {
+ for (int i = existingUserState.suspendParams.size() - 1; i >= 0; i--) {
+ final String suspendingPackage = existingUserState.suspendParams.keyAt(i);
+ if (suspendingPackagePredicate.test(suspendingPackage)) {
+ existingUserState.suspendParams.removeAt(i);
+ }
+ }
+ if (existingUserState.suspendParams.size() == 0) {
+ existingUserState.suspendParams = null;
+ }
+ }
+ existingUserState.suspended = (existingUserState.suspendParams != null);
+ }
+
public boolean getInstantApp(int userId) {
return readUserState(userId).instantApp;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 2de9858d91f9..c8df5c731845 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -36,6 +36,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.DumpFilter;
@@ -365,9 +366,12 @@ class ShortcutPackage extends ShortcutPackageItem {
/**
* Remove all shortcuts that aren't pinned, cached nor dynamic.
+ *
+ * @return List of removed shortcuts.
*/
- private void removeOrphans() {
+ private List<ShortcutInfo> removeOrphans() {
ArrayList<String> removeList = null; // Lazily initialize.
+ List<ShortcutInfo> removedShortcuts = null;
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -376,20 +380,26 @@ class ShortcutPackage extends ShortcutPackageItem {
if (removeList == null) {
removeList = new ArrayList<>();
+ removedShortcuts = new ArrayList<>();
}
removeList.add(si.getId());
+ removedShortcuts.add(si);
}
if (removeList != null) {
for (int i = removeList.size() - 1; i >= 0; i--) {
forceDeleteShortcutInner(removeList.get(i));
}
}
+
+ return removedShortcuts;
}
/**
* Remove all dynamic shortcuts.
+ *
+ * @return List of shortcuts that actually got removed.
*/
- public void deleteAllDynamicShortcuts(boolean ignoreInvisible) {
+ public List<ShortcutInfo> deleteAllDynamicShortcuts(boolean ignoreInvisible) {
final long now = mShortcutUser.mService.injectCurrentTimeMillis();
boolean changed = false;
@@ -404,8 +414,9 @@ class ShortcutPackage extends ShortcutPackageItem {
}
}
if (changed) {
- removeOrphans();
+ return removeOrphans();
}
+ return null;
}
/**
@@ -1028,7 +1039,8 @@ class ShortcutPackage extends ShortcutPackageItem {
s.verifyStates();
// This will send a notification to the launcher, and also save .
- s.packageShortcutsChanged(getPackageName(), getPackageUserId());
+ // TODO: List changed and removed manifest shortcuts and pass to packageShortcutsChanged()
+ s.packageShortcutsChanged(getPackageName(), getPackageUserId(), null, null);
return true; // true means changed.
}
@@ -1299,15 +1311,14 @@ class ShortcutPackage extends ShortcutPackageItem {
*/
public void resolveResourceStrings() {
final ShortcutService s = mShortcutUser.mService;
- boolean changed = false;
+
+ List<ShortcutInfo> changedShortcuts = null;
Resources publisherRes = null;
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
if (si.hasStringResources()) {
- changed = true;
-
if (publisherRes == null) {
publisherRes = getPackageResources();
if (publisherRes == null) {
@@ -1317,10 +1328,15 @@ class ShortcutPackage extends ShortcutPackageItem {
si.resolveResourceStrings(publisherRes);
si.setTimestamp(s.injectCurrentTimeMillis());
+
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
}
}
- if (changed) {
- s.packageShortcutsChanged(getPackageName(), getPackageUserId());
+ if (!CollectionUtils.isEmpty(changedShortcuts)) {
+ s.packageShortcutsChanged(getPackageName(), getPackageUserId(), changedShortcuts, null);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 3e44de989c7c..6fd997db8be8 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -26,7 +26,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -36,6 +35,9 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Handles {@link android.content.pm.ShortcutManager#requestPinShortcut} related tasks.
*/
@@ -452,6 +454,8 @@ class ShortcutRequestPinProcessor {
final String launcherPackage = request.launcherPackage;
final String shortcutId = original.getId();
+ List<ShortcutInfo> changedShortcuts = null;
+
synchronized (mLock) {
if (!(mService.isUserUnlockedL(appUserId)
&& mService.isUserUnlockedL(request.launcherUserId))) {
@@ -506,8 +510,13 @@ class ShortcutRequestPinProcessor {
Slog.d(TAG, "Pinning " + shortcutId);
}
+
launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId,
/*forPinRequest=*/ true);
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(original);
if (current == null) {
if (DEBUG) {
@@ -520,7 +529,7 @@ class ShortcutRequestPinProcessor {
}
mService.verifyStates();
- mService.packageShortcutsChanged(appPackageName, appUserId);
+ mService.packageShortcutsChanged(appPackageName, appUserId, changedShortcuts, null);
return true;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 54f9f761241f..66f3574d83a0 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -98,6 +98,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -277,6 +278,10 @@ public class ShortcutService extends IShortcutService.Stub {
private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
@GuardedBy("mLock")
+ private final ArrayList<LauncherApps.ShortcutChangeCallback> mShortcutChangeCallbacks =
+ new ArrayList<>(1);
+
+ @GuardedBy("mLock")
private long mRawLastResetTime;
/**
@@ -1639,8 +1644,12 @@ public class ShortcutService extends IShortcutService.Stub {
* - Sends a notification to LauncherApps
* - Write to file
*/
- void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId) {
+ void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId,
+ @Nullable List<ShortcutInfo> addedOrUpdatedShortcuts,
+ @Nullable List<ShortcutInfo> removedShortcuts) {
notifyListeners(packageName, userId);
+ notifyShortcutChangeCallbacks(packageName, userId, addedOrUpdatedShortcuts,
+ removedShortcuts);
scheduleSaveUser(userId);
}
@@ -1668,6 +1677,34 @@ public class ShortcutService extends IShortcutService.Stub {
});
}
+ private void notifyShortcutChangeCallbacks(@NonNull String packageName, @UserIdInt int userId,
+ @Nullable List<ShortcutInfo> addedOrUpdatedShortcuts,
+ @Nullable List<ShortcutInfo> removedShortcuts) {
+ final UserHandle user = UserHandle.of(userId);
+ injectPostToHandler(() -> {
+ try {
+ final ArrayList<LauncherApps.ShortcutChangeCallback> copy;
+ synchronized (mLock) {
+ if (!isUserUnlockedL(userId)) {
+ return;
+ }
+
+ copy = new ArrayList<>(mShortcutChangeCallbacks);
+ }
+ for (int i = copy.size() - 1; i >= 0; i--) {
+ if (!CollectionUtils.isEmpty(addedOrUpdatedShortcuts)) {
+ copy.get(i).onShortcutsAddedOrUpdated(packageName, addedOrUpdatedShortcuts,
+ user);
+ }
+ if (!CollectionUtils.isEmpty(removedShortcuts)) {
+ copy.get(i).onShortcutsRemoved(packageName, removedShortcuts, user);
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ });
+ }
+
/**
* Clean up / validate an incoming shortcut.
* - Make sure all mandatory fields are set.
@@ -1762,6 +1799,8 @@ public class ShortcutService extends IShortcutService.Stub {
final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
injectBinderCallingPid(), injectBinderCallingUid());
+ List<ShortcutInfo> removedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -1787,7 +1826,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
// First, remove all un-pinned; dynamic shortcuts
- ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
+ removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
// Then, add/update all. We need to make sure to take over "pinned" flag.
for (int i = 0; i < size; i++) {
@@ -1798,7 +1837,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, newShortcuts, removedShortcuts);
verifyStates();
@@ -1817,6 +1856,8 @@ public class ShortcutService extends IShortcutService.Stub {
final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
injectBinderCallingPid(), injectBinderCallingUid());
+ List<ShortcutInfo> changedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -1879,12 +1920,17 @@ public class ShortcutService extends IShortcutService.Stub {
if (replacingIcon || source.hasStringResources()) {
fixUpShortcutResourceNamesAndValues(target);
}
+
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(target);
}
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, changedShortcuts, null);
verifyStates();
@@ -1903,6 +1949,8 @@ public class ShortcutService extends IShortcutService.Stub {
final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
injectBinderCallingPid(), injectBinderCallingUid());
+ List<ShortcutInfo> changedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -1934,12 +1982,17 @@ public class ShortcutService extends IShortcutService.Stub {
// Add it.
ps.addOrReplaceDynamicShortcut(newShortcut);
+
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(newShortcut);
}
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, changedShortcuts, null);
verifyStates();
@@ -1985,7 +2038,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Lastly, adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, Collections.singletonList(shortcut), null);
verifyStates();
}
@@ -2052,7 +2105,8 @@ public class ShortcutService extends IShortcutService.Stub {
ps.updateInvisibleShortcutForPinRequestWith(shortcut);
- packageShortcutsChanged(shortcutPackage, userId);
+ packageShortcutsChanged(shortcutPackage, userId,
+ Collections.singletonList(shortcut), null);
}
}
@@ -2097,7 +2151,8 @@ public class ShortcutService extends IShortcutService.Stub {
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ // TODO: Disabling dynamic shortcuts will removed them if not pinned. Cover all cases.
+ packageShortcutsChanged(packageName, userId, null, null);
verifyStates();
}
@@ -2107,6 +2162,8 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
+ List<ShortcutInfo> changedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -2121,9 +2178,18 @@ public class ShortcutService extends IShortcutService.Stub {
continue;
}
ps.enableWithId(id);
+
+ final ShortcutInfo si = ps.findShortcutById(id);
+ if (si != null) {
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
+ }
}
}
- packageShortcutsChanged(packageName, userId);
+
+ packageShortcutsChanged(packageName, userId, changedShortcuts, null);
verifyStates();
}
@@ -2134,6 +2200,9 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
+ List<ShortcutInfo> changedShortcuts = null;
+ List<ShortcutInfo> removedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -2147,13 +2216,25 @@ public class ShortcutService extends IShortcutService.Stub {
if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
continue;
}
- ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
+ final ShortcutInfo si = ps.findShortcutById(id);
+ final boolean removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
+ if (removed) {
+ if (removedShortcuts == null) {
+ removedShortcuts = new ArrayList<>(1);
+ }
+ removedShortcuts.add(si);
+ } else {
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
+ }
}
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2162,13 +2243,19 @@ public class ShortcutService extends IShortcutService.Stub {
public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
+ List<ShortcutInfo> changedShortcuts = null;
+ List<ShortcutInfo> removedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
- ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
+
+ removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
}
- packageShortcutsChanged(packageName, userId);
+
+ // TODO: Pinned and cached shortcuts are not removed, add those to changedShortcuts list
+ packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2179,6 +2266,9 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Objects.requireNonNull(shortcutIds, "shortcutIds must be provided");
+ List<ShortcutInfo> changedShortcuts = null;
+ List<ShortcutInfo> removedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
@@ -2189,13 +2279,29 @@ public class ShortcutService extends IShortcutService.Stub {
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
- ps.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+
+ final ShortcutInfo si = ps.findShortcutById(id);
+ final boolean removed = ps.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+
+ if (si != null) {
+ if (removed) {
+ if (removedShortcuts == null) {
+ removedShortcuts = new ArrayList<>(1);
+ }
+ removedShortcuts.add(si);
+ } else {
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
+ }
+ }
}
// We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
ps.adjustRanks();
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2787,6 +2893,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(shortcutIds, "shortcutIds");
+ List<ShortcutInfo> changedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
throwIfUserLockedL(launcherUserId);
@@ -2796,8 +2904,23 @@ public class ShortcutService extends IShortcutService.Stub {
launcher.attemptToRestoreIfNeededAndSave();
launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false);
+
+ final ShortcutPackage sp = getUserShortcutsLocked(userId)
+ .getPackageShortcutsIfExists(packageName);
+ if (sp != null) {
+ for (int i = 0; i < shortcutIds.size(); i++) {
+ final ShortcutInfo si = sp.findShortcutById(shortcutIds.get(i));
+ if (si != null) {
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
+ }
+ }
+ }
}
- packageShortcutsChanged(packageName, userId);
+ // TODO: Include previously pinned shortcuts since they are not pinned anymore.
+ packageShortcutsChanged(packageName, userId, changedShortcuts, null);
verifyStates();
}
@@ -2832,6 +2955,9 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(shortcutIds, "shortcutIds");
+ List<ShortcutInfo> changedShortcuts = null;
+ List<ShortcutInfo> removedShortcuts = null;
+
synchronized (mLock) {
throwIfUserLockedL(userId);
throwIfUserLockedL(launcherUserId);
@@ -2853,20 +2979,36 @@ public class ShortcutService extends IShortcutService.Stub {
if (doCache) {
if (si.isDynamic() && si.isLongLived()) {
si.addFlags(ShortcutInfo.FLAG_CACHED);
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
} else {
Log.w(TAG, "Only dynamic long lived shortcuts can get cached. Ignoring"
+ "shortcut " + si.getId());
}
} else {
+ boolean removed = false;
if (si.isDynamic()) {
si.clearFlags(ShortcutInfo.FLAG_CACHED);
} else {
- sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+ removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
+ }
+ if (removed) {
+ if (removedShortcuts == null) {
+ removedShortcuts = new ArrayList<>(1);
+ }
+ removedShortcuts.add(si);
+ } else {
+ if (changedShortcuts == null) {
+ changedShortcuts = new ArrayList<>(1);
+ }
+ changedShortcuts.add(si);
}
}
}
}
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(packageName, userId, changedShortcuts, removedShortcuts);
verifyStates();
}
@@ -2912,6 +3054,14 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
+ public void addShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback) {
+ synchronized (mLock) {
+ mShortcutChangeCallbacks.add(Objects.requireNonNull(callback));
+ }
+ }
+
+ @Override
public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
Objects.requireNonNull(callingPackage, "callingPackage");
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 67b1008333e1..8d3f32aab9c5 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -26,6 +26,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
@@ -42,6 +43,7 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
import com.google.android.collect.Sets;
@@ -585,6 +587,9 @@ public class UserRestrictionsUtils {
android.provider.Settings.Global.putStringForUser(cr,
android.provider.Settings.Global.ADB_ENABLED, "0",
userId);
+ android.provider.Settings.Global.putStringForUser(cr,
+ android.provider.Settings.Global.ADB_WIFI_ENABLED, "0",
+ userId);
}
}
break;
@@ -676,6 +681,15 @@ public class UserRestrictionsUtils {
Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
}
break;
+ case UserManager.DISALLOW_APPS_CONTROL:
+ // Intentional fall-through
+ case UserManager.DISALLOW_UNINSTALL_APPS:
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ pmi.removeAllNonSystemPackageSuspensions(userId);
+ pmi.removeAllDistractingPackageRestrictions(userId);
+ pmi.flushPackageRestrictions(userId);
+ break;
}
} finally {
Binder.restoreCallingIdentity(id);
@@ -721,6 +735,7 @@ public class UserRestrictionsUtils {
break;
case android.provider.Settings.Global.ADB_ENABLED:
+ case android.provider.Settings.Global.ADB_WIFI_ENABLED:
if ("0".equals(value)) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 9c945d5a7ea8..48dd9e6f86ec 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -152,8 +152,8 @@ public final class DefaultPermissionGrantPolicy {
private static final Set<String> FOREGROUND_LOCATION_PERMISSIONS = new ArraySet<>();
static {
- ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
- ALWAYS_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+ FOREGROUND_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
+ FOREGROUND_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
private static final Set<String> COARSE_BACKGROUND_LOCATION_PERMISSIONS = new ArraySet<>();
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index da3cbf9d03b4..74c3a9ec375b 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -370,30 +370,33 @@ public class ThermalManagerService extends SystemService {
}
@Override
- public List<Temperature> getCurrentTemperatures() {
+ public Temperature[] getCurrentTemperatures() {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
if (!mHalReady.get()) {
- return new ArrayList<>();
+ return new Temperature[0];
}
- return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
+ final List<Temperature> curr = mHalWrapper.getCurrentTemperatures(
+ false, 0 /* not used */);
+ return curr.toArray(new Temperature[curr.size()]);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public List<Temperature> getCurrentTemperaturesWithType(int type) {
+ public Temperature[] getCurrentTemperaturesWithType(int type) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
if (!mHalReady.get()) {
- return new ArrayList<>();
+ return new Temperature[0];
}
- return mHalWrapper.getCurrentTemperatures(true, type);
+ final List<Temperature> curr = mHalWrapper.getCurrentTemperatures(true, type);
+ return curr.toArray(new Temperature[curr.size()]);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -443,30 +446,34 @@ public class ThermalManagerService extends SystemService {
}
@Override
- public List<CoolingDevice> getCurrentCoolingDevices() {
+ public CoolingDevice[] getCurrentCoolingDevices() {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
if (!mHalReady.get()) {
- return new ArrayList<>();
+ return new CoolingDevice[0];
}
- return mHalWrapper.getCurrentCoolingDevices(false, 0);
+ final List<CoolingDevice> devList = mHalWrapper.getCurrentCoolingDevices(
+ false, 0);
+ return devList.toArray(new CoolingDevice[devList.size()]);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) {
+ public CoolingDevice[] getCurrentCoolingDevicesWithType(int type) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
if (!mHalReady.get()) {
- return new ArrayList<>();
+ return new CoolingDevice[0];
}
- return mHalWrapper.getCurrentCoolingDevices(true, type);
+ final List<CoolingDevice> devList = mHalWrapper.getCurrentCoolingDevices(
+ true, type);
+ return devList.toArray(new CoolingDevice[devList.size()]);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 47a26f576949..aed2d9bb9dc7 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -41,6 +41,7 @@ import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
import android.app.INotificationManager;
import android.app.ProcessMemoryState;
+import android.app.RuntimeAppOpAccessMessage;
import android.app.StatsManager;
import android.app.StatsManager.PullAtomMetadata;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -81,6 +82,7 @@ import android.os.SynchronousResultReceiver;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Temperature;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.connectivity.WifiActivityEnergyInfo;
@@ -270,125 +272,134 @@ public class StatsPullAtomService extends SystemService {
private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
@Override
public int onPullAtom(int atomTag, List<StatsEvent> data) {
- switch(atomTag) {
- case FrameworkStatsLog.WIFI_BYTES_TRANSFER:
- return pullWifiBytesTransfer(atomTag, data);
- case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
- return pullWifiBytesTransferBackground(atomTag, data);
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
- return pullMobileBytesTransfer(atomTag, data);
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
- return pullMobileBytesTransferBackground(atomTag, data);
- case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
- return pullBluetoothBytesTransfer(atomTag, data);
- case FrameworkStatsLog.KERNEL_WAKELOCK:
- return pullKernelWakelock(atomTag, data);
- case FrameworkStatsLog.CPU_TIME_PER_FREQ:
- return pullCpuTimePerFreq(atomTag, data);
- case FrameworkStatsLog.CPU_TIME_PER_UID:
- return pullCpuTimePerUid(atomTag, data);
- case FrameworkStatsLog.CPU_TIME_PER_UID_FREQ:
- return pullCpuTimeperUidFreq(atomTag, data);
- case FrameworkStatsLog.CPU_ACTIVE_TIME:
- return pullCpuActiveTime(atomTag, data);
- case FrameworkStatsLog.CPU_CLUSTER_TIME:
- return pullCpuClusterTime(atomTag, data);
- case FrameworkStatsLog.WIFI_ACTIVITY_INFO:
- return pullWifiActivityInfo(atomTag, data);
- case FrameworkStatsLog.MODEM_ACTIVITY_INFO:
- return pullModemActivityInfo(atomTag, data);
- case FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO:
- return pullBluetoothActivityInfo(atomTag, data);
- case FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME:
- return pullSystemElapsedRealtime(atomTag, data);
- case FrameworkStatsLog.SYSTEM_UPTIME:
- return pullSystemUptime(atomTag, data);
- case FrameworkStatsLog.PROCESS_MEMORY_STATE:
- return pullProcessMemoryState(atomTag, data);
- case FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK:
- return pullProcessMemoryHighWaterMark(atomTag, data);
- case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT:
- return pullProcessMemorySnapshot(atomTag, data);
- case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE:
- return pullSystemIonHeapSize(atomTag, data);
- case FrameworkStatsLog.ION_HEAP_SIZE:
- return pullIonHeapSize(atomTag, data);
- case FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE:
- return pullProcessSystemIonHeapSize(atomTag, data);
- case FrameworkStatsLog.TEMPERATURE:
- return pullTemperature(atomTag, data);
- case FrameworkStatsLog.COOLING_DEVICE:
- return pullCooldownDevice(atomTag, data);
- case FrameworkStatsLog.BINDER_CALLS:
- return pullBinderCallsStats(atomTag, data);
- case FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS:
- return pullBinderCallsStatsExceptions(atomTag, data);
- case FrameworkStatsLog.LOOPER_STATS:
- return pullLooperStats(atomTag, data);
- case FrameworkStatsLog.DISK_STATS:
- return pullDiskStats(atomTag, data);
- case FrameworkStatsLog.DIRECTORY_USAGE:
- return pullDirectoryUsage(atomTag, data);
- case FrameworkStatsLog.APP_SIZE:
- return pullAppSize(atomTag, data);
- case FrameworkStatsLog.CATEGORY_SIZE:
- return pullCategorySize(atomTag, data);
- case FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED:
- return pullNumBiometricsEnrolled(
- BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
- case FrameworkStatsLog.NUM_FACES_ENROLLED:
- return pullNumBiometricsEnrolled(
- BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
- case FrameworkStatsLog.PROC_STATS:
- return pullProcStats(ProcessStats.REPORT_ALL, atomTag, data);
- case FrameworkStatsLog.PROC_STATS_PKG_PROC:
- return pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data);
- case FrameworkStatsLog.DISK_IO:
- return pullDiskIO(atomTag, data);
- case FrameworkStatsLog.POWER_PROFILE:
- return pullPowerProfile(atomTag, data);
- case FrameworkStatsLog.PROCESS_CPU_TIME:
- return pullProcessCpuTime(atomTag, data);
- case FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ:
- return pullCpuTimePerThreadFreq(atomTag, data);
- case FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE:
- return pullDeviceCalculatedPowerUse(atomTag, data);
- case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID:
- return pullDeviceCalculatedPowerBlameUid(atomTag, data);
- case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER:
- return pullDeviceCalculatedPowerBlameOther(atomTag, data);
- case FrameworkStatsLog.DEBUG_ELAPSED_CLOCK:
- return pullDebugElapsedClock(atomTag, data);
- case FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK:
- return pullDebugFailingElapsedClock(atomTag, data);
- case FrameworkStatsLog.BUILD_INFORMATION:
- return pullBuildInformation(atomTag, data);
- case FrameworkStatsLog.ROLE_HOLDER:
- return pullRoleHolder(atomTag, data);
- case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE:
- return pullDangerousPermissionState(atomTag, data);
- case FrameworkStatsLog.TIME_ZONE_DATA_INFO:
- return pullTimeZoneDataInfo(atomTag, data);
- case FrameworkStatsLog.EXTERNAL_STORAGE_INFO:
- return pullExternalStorageInfo(atomTag, data);
- case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO:
- return pullAppsOnExternalStorageInfo(atomTag, data);
- case FrameworkStatsLog.FACE_SETTINGS:
- return pullFaceSettings(atomTag, data);
- case FrameworkStatsLog.APP_OPS:
- return pullAppOps(atomTag, data);
- case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
- return pullNotificationRemoteViews(atomTag, data);
- case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
- return pullDangerousPermissionState(atomTag, data);
- case FrameworkStatsLog.BATTERY_LEVEL:
- case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
- case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
- case FrameworkStatsLog.BATTERY_VOLTAGE:
- case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
- return pullHealthHal(atomTag, data);
- default:
- throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StatsPull-" + atomTag);
+ }
+ try {
+ switch (atomTag) {
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER:
+ return pullWifiBytesTransfer(atomTag, data);
+ case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG:
+ return pullWifiBytesTransferBackground(atomTag, data);
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
+ return pullMobileBytesTransfer(atomTag, data);
+ case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
+ return pullMobileBytesTransferBackground(atomTag, data);
+ case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
+ return pullBluetoothBytesTransfer(atomTag, data);
+ case FrameworkStatsLog.KERNEL_WAKELOCK:
+ return pullKernelWakelock(atomTag, data);
+ case FrameworkStatsLog.CPU_TIME_PER_FREQ:
+ return pullCpuTimePerFreq(atomTag, data);
+ case FrameworkStatsLog.CPU_TIME_PER_UID:
+ return pullCpuTimePerUid(atomTag, data);
+ case FrameworkStatsLog.CPU_TIME_PER_UID_FREQ:
+ return pullCpuTimeperUidFreq(atomTag, data);
+ case FrameworkStatsLog.CPU_ACTIVE_TIME:
+ return pullCpuActiveTime(atomTag, data);
+ case FrameworkStatsLog.CPU_CLUSTER_TIME:
+ return pullCpuClusterTime(atomTag, data);
+ case FrameworkStatsLog.WIFI_ACTIVITY_INFO:
+ return pullWifiActivityInfo(atomTag, data);
+ case FrameworkStatsLog.MODEM_ACTIVITY_INFO:
+ return pullModemActivityInfo(atomTag, data);
+ case FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO:
+ return pullBluetoothActivityInfo(atomTag, data);
+ case FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME:
+ return pullSystemElapsedRealtime(atomTag, data);
+ case FrameworkStatsLog.SYSTEM_UPTIME:
+ return pullSystemUptime(atomTag, data);
+ case FrameworkStatsLog.PROCESS_MEMORY_STATE:
+ return pullProcessMemoryState(atomTag, data);
+ case FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK:
+ return pullProcessMemoryHighWaterMark(atomTag, data);
+ case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT:
+ return pullProcessMemorySnapshot(atomTag, data);
+ case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE:
+ return pullSystemIonHeapSize(atomTag, data);
+ case FrameworkStatsLog.ION_HEAP_SIZE:
+ return pullIonHeapSize(atomTag, data);
+ case FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE:
+ return pullProcessSystemIonHeapSize(atomTag, data);
+ case FrameworkStatsLog.TEMPERATURE:
+ return pullTemperature(atomTag, data);
+ case FrameworkStatsLog.COOLING_DEVICE:
+ return pullCooldownDevice(atomTag, data);
+ case FrameworkStatsLog.BINDER_CALLS:
+ return pullBinderCallsStats(atomTag, data);
+ case FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS:
+ return pullBinderCallsStatsExceptions(atomTag, data);
+ case FrameworkStatsLog.LOOPER_STATS:
+ return pullLooperStats(atomTag, data);
+ case FrameworkStatsLog.DISK_STATS:
+ return pullDiskStats(atomTag, data);
+ case FrameworkStatsLog.DIRECTORY_USAGE:
+ return pullDirectoryUsage(atomTag, data);
+ case FrameworkStatsLog.APP_SIZE:
+ return pullAppSize(atomTag, data);
+ case FrameworkStatsLog.CATEGORY_SIZE:
+ return pullCategorySize(atomTag, data);
+ case FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED:
+ return pullNumBiometricsEnrolled(
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
+ case FrameworkStatsLog.NUM_FACES_ENROLLED:
+ return pullNumBiometricsEnrolled(
+ BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
+ case FrameworkStatsLog.PROC_STATS:
+ return pullProcStats(ProcessStats.REPORT_ALL, atomTag, data);
+ case FrameworkStatsLog.PROC_STATS_PKG_PROC:
+ return pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data);
+ case FrameworkStatsLog.DISK_IO:
+ return pullDiskIO(atomTag, data);
+ case FrameworkStatsLog.POWER_PROFILE:
+ return pullPowerProfile(atomTag, data);
+ case FrameworkStatsLog.PROCESS_CPU_TIME:
+ return pullProcessCpuTime(atomTag, data);
+ case FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ:
+ return pullCpuTimePerThreadFreq(atomTag, data);
+ case FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE:
+ return pullDeviceCalculatedPowerUse(atomTag, data);
+ case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID:
+ return pullDeviceCalculatedPowerBlameUid(atomTag, data);
+ case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER:
+ return pullDeviceCalculatedPowerBlameOther(atomTag, data);
+ case FrameworkStatsLog.DEBUG_ELAPSED_CLOCK:
+ return pullDebugElapsedClock(atomTag, data);
+ case FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK:
+ return pullDebugFailingElapsedClock(atomTag, data);
+ case FrameworkStatsLog.BUILD_INFORMATION:
+ return pullBuildInformation(atomTag, data);
+ case FrameworkStatsLog.ROLE_HOLDER:
+ return pullRoleHolder(atomTag, data);
+ case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE:
+ return pullDangerousPermissionState(atomTag, data);
+ case FrameworkStatsLog.TIME_ZONE_DATA_INFO:
+ return pullTimeZoneDataInfo(atomTag, data);
+ case FrameworkStatsLog.EXTERNAL_STORAGE_INFO:
+ return pullExternalStorageInfo(atomTag, data);
+ case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO:
+ return pullAppsOnExternalStorageInfo(atomTag, data);
+ case FrameworkStatsLog.FACE_SETTINGS:
+ return pullFaceSettings(atomTag, data);
+ case FrameworkStatsLog.APP_OPS:
+ return pullAppOps(atomTag, data);
+ case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
+ return pullRuntimeAppOpAccessMessage(atomTag, data);
+ case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
+ return pullNotificationRemoteViews(atomTag, data);
+ case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
+ return pullDangerousPermissionState(atomTag, data);
+ case FrameworkStatsLog.BATTERY_LEVEL:
+ case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
+ case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
+ case FrameworkStatsLog.BATTERY_VOLTAGE:
+ case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
+ return pullHealthHal(atomTag, data);
+ default:
+ throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
}
@@ -539,6 +550,7 @@ public class StatsPullAtomService extends SystemService {
registerAppsOnExternalStorageInfo();
registerFaceSettings();
registerAppOps();
+ registerRuntimeAppOpAccessMessage();
registerNotificationRemoteViews();
registerDangerousPermissionState();
registerDangerousPermissionStateSampled();
@@ -1515,7 +1527,7 @@ public class StatsPullAtomService extends SystemService {
}
final long callingToken = Binder.clearCallingIdentity();
try {
- List<Temperature> temperatures = thermalService.getCurrentTemperatures();
+ Temperature temperatures[] = thermalService.getCurrentTemperatures();
for (Temperature temp : temperatures) {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -1553,7 +1565,7 @@ public class StatsPullAtomService extends SystemService {
}
final long callingToken = Binder.clearCallingIdentity();
try {
- List<CoolingDevice> devices = thermalService.getCurrentCoolingDevices();
+ CoolingDevice devices[] = thermalService.getCurrentCoolingDevices();
for (CoolingDevice device : devices) {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -2834,6 +2846,17 @@ public class StatsPullAtomService extends SystemService {
}
+ private void registerRuntimeAppOpAccessMessage() {
+ int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ BackgroundThread.getExecutor(),
+ mStatsCallbackImpl
+ );
+
+ }
+
int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
@@ -2894,6 +2917,41 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SUCCESS;
}
+ int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+
+ RuntimeAppOpAccessMessage message = appOps.collectRuntimeAppOpAccessMessage();
+ if (message == null) {
+ Slog.i(TAG, "No runtime appop access message collected");
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ StatsEvent.Builder e = StatsEvent.newBuilder();
+ e.setAtomId(atomTag);
+ e.writeInt(message.getUid());
+ e.writeString(message.getPackageName());
+ e.writeString(message.getOp());
+ if (message.getFeatureId() == null) {
+ e.writeString("");
+ } else {
+ e.writeString(message.getFeatureId());
+ }
+ e.writeString(message.getMessage());
+ e.writeInt(message.getSamplingStrategy());
+
+ pulledData.add(e.build());
+ } catch (Throwable t) {
+ // TODO: catch exceptions at a more granular level
+ Slog.e(TAG, "Could not read runtime appop access message", t);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
static void unpackStreamedData(int atomTag, List<StatsEvent> pulledData,
List<ParcelFileDescriptor> statsFiles) throws IOException {
InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 5b892f808e2f..deaec0ac75ae 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -158,7 +158,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
final File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
- null /* processCpuTracker */, null /* lastPids */, nativePids);
+ null /* processCpuTracker */, null /* lastPids */, nativePids,
+ null /* logExceptionCreatingFile */);
if (tracesFile != null) {
tracesFile.renameTo(new File(tracesFile.getParent(), tracesFile.getName() + "_pre"));
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 68b8348e706f..337764ae32f5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1169,10 +1169,9 @@ public class WindowManagerService extends IWindowManager.Stub
mAnimator = new WindowAnimator(this);
mRoot = new RootWindowContainer(this);
- mUseBLAST = SystemProperties.getBoolean(
- String.join(".", "persist.device_config",
+ mUseBLAST = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
- WM_USE_BLAST_ADAPTER_FLAG), false);
+ WM_USE_BLAST_ADAPTER_FLAG, false);
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
@@ -2584,11 +2583,18 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void addWindowToken(IBinder binder, int type, int displayId) {
addWindowTokenWithOptions(binder, type, displayId, null /* options */,
- null /* packageName */);
+ null /* packageName */, false /* fromClientToken */);
}
+ @Override
public int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
String packageName) {
+ return addWindowTokenWithOptions(binder, type, displayId, options, packageName,
+ true /* fromClientToken */);
+ }
+
+ private int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
+ String packageName, boolean fromClientToken) {
final boolean callerCanManageAppTokens =
checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()");
if (!callerCanManageAppTokens) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 48c7812afec0..76a03150c8df 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -23,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.ProtoLogGroup.WM_ERROR;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -36,10 +38,12 @@ import static com.android.server.wm.WindowTokenProto.WINDOWS;
import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
+import android.app.IWindowToken;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
+import android.os.RemoteException;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.InsetsState;
@@ -91,6 +95,11 @@ class WindowToken extends WindowContainer<WindowState> {
private FixedRotationTransformState mFixedRotationTransformState;
+ private Configuration mLastReportedConfig;
+ private int mLastReportedDisplay = INVALID_DISPLAY;
+
+ private final boolean mFromClientToken;
+
/**
* Used to fix the transform of the token to be rotated to a rotation different than it's
* display. The window frames and surfaces corresponding to this token will be layouted and
@@ -167,13 +176,21 @@ class WindowToken extends WindowContainer<WindowState> {
}
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
- DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
+ DisplayContent dc, boolean ownerCanManageAppTokens, boolean fromClientToken) {
+ this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
+ false /* roundedCornersOverlay */, fromClientToken);
+ }
+
+ WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
+ DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay,
+ boolean fromClientToken) {
super(service);
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
+ mFromClientToken = fromClientToken;
if (dc != null) {
dc.addWindowToken(token, this);
}
@@ -305,8 +322,47 @@ class WindowToken extends WindowContainer<WindowState> {
// up with goodToGo, so we don't move a window
// to another display before the window behind
// it is ready.
-
super.onDisplayChanged(dc);
+ reportConfigToWindowTokenClient();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+ reportConfigToWindowTokenClient();
+ }
+
+ void reportConfigToWindowTokenClient() {
+ if (asActivityRecord() != null) {
+ // Activities are updated through ATM callbacks.
+ return;
+ }
+
+ // Unfortunately, this WindowToken is not from WindowContext so it cannot handle
+ // its own configuration changes.
+ if (!mFromClientToken) {
+ return;
+ }
+
+ final Configuration config = getConfiguration();
+ final int displayId = getDisplayContent().getDisplayId();
+ if (config.equals(mLastReportedConfig) && displayId == mLastReportedDisplay) {
+ // No changes since last reported time.
+ return;
+ }
+
+ mLastReportedConfig = config;
+ mLastReportedDisplay = displayId;
+
+ IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(token);
+ if (windowTokenClient != null) {
+ try {
+ windowTokenClient.onConfigurationChanged(config, displayId);
+ } catch (RemoteException e) {
+ ProtoLog.w(WM_ERROR,
+ "Could not report config changes to the window token client.");
+ }
+ }
}
@Override
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8772edd73845..e0d40452590b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -27,8 +27,6 @@
#define DEBUG_INPUT_DISPATCHER_POLICY 0
-#include <nativehelper/JNIHelp.h>
-#include "jni.h"
#include <atomic>
#include <cinttypes>
#include <limits.h>
@@ -50,7 +48,6 @@
#include <inputflinger/InputManager.h>
-#include <android/graphics/GraphicsJNI.h>
#include <android_os_MessageQueue.h>
#include <android_view_InputChannel.h>
#include <android_view_InputDevice.h>
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 70a9c09c815d..f445aa810753 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -190,6 +190,7 @@ static inline std::vector<char> readBytes(borrowed_fd fd) {
}
static inline int32_t skipIdSigHeaders(borrowed_fd fd) {
+ readBEInt32(fd); // version
readBytes(fd); // verityRootHash
readBytes(fd); // v3Digest
readBytes(fd); // pkcs7SignatureBlock
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index e57543203634..f9238e3977c6 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/graphics/jni_runtime.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "utils/Log.h"
@@ -49,7 +50,6 @@ int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
-int register_android_graphics_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 012fdfc5bbd0..440b779b8566 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -186,7 +186,6 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.location.LocationManager;
-import android.location.LocationManagerInternal;
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
@@ -445,10 +444,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
/**
- * System property whose value is either "true" or "false", indicating whether
- * device owner is present.
+ * System property whose value indicates whether the device is fully owned by an organization:
+ * it can be either a device owner device, or a device with an organization-owned managed
+ * profile.
+ *
+ * <p>The state is stored as a Boolean string.
*/
- private static final String PROPERTY_DEVICE_OWNER_PRESENT = "ro.organization_owned";
+ private static final String PROPERTY_ORGANIZATION_OWNED = "ro.organization_owned";
private static final int STATUS_BAR_DISABLE_MASK =
StatusBarManager.DISABLE_EXPAND |
@@ -481,6 +483,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
GLOBAL_SETTINGS_WHITELIST = new ArraySet<>();
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
+ GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_WIFI_ENABLED);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING);
@@ -2131,10 +2134,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(LocationManager.class);
}
- LocationManagerInternal getLocationManagerInternal() {
- return LocalServices.getService(LocationManagerInternal.class);
- }
-
IWindowManager getIWindowManager() {
return IWindowManager.Stub
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -2555,7 +2554,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
void loadOwners() {
synchronized (getLockObject()) {
mOwners.load();
- setDeviceOwnerSystemPropertyLocked();
+ setDeviceOwnershipSystemPropertyLocked();
findOwnerComponentIfNecessaryLocked();
migrateUserRestrictionsIfNecessaryLocked();
@@ -2757,34 +2756,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private void setDeviceOwnerSystemPropertyLocked() {
+ private void setDeviceOwnershipSystemPropertyLocked() {
+ // Still at the first stage of CryptKeeper double bounce, nothing can be learnt about
+ // the real system at this point.
+ if (StorageManager.inCryptKeeperBounce()) {
+ return;
+ }
final boolean deviceProvisioned =
mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
final boolean hasDeviceOwner = mOwners.hasDeviceOwner();
- // If the device is not provisioned and there is currently no device owner, do not set the
- // read-only system property yet, since Device owner may still be provisioned.
- if (!hasDeviceOwner && !deviceProvisioned) {
+ final boolean hasOrgOwnedProfile = isOrganizationOwnedDeviceWithManagedProfile();
+ // If the device is not provisioned and there is currently no management, do not set the
+ // read-only system property yet, since device owner / org-owned profile may still be
+ // provisioned.
+ if (!hasDeviceOwner && !hasOrgOwnedProfile && !deviceProvisioned) {
return;
}
- // Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
- // always false at this point.
- if (StorageManager.inCryptKeeperBounce()) {
- return;
- }
-
- if (!mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT, "").isEmpty()) {
- Slog.w(LOG_TAG, "Trying to set ro.organization_owned, but it has already been set?");
- } else {
- final String value = Boolean.toString(hasDeviceOwner);
- mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, value);
+ final String value = Boolean.toString(hasDeviceOwner || hasOrgOwnedProfile);
+ final String currentVal = mInjector.systemPropertiesGet(PROPERTY_ORGANIZATION_OWNED, null);
+ if (TextUtils.isEmpty(currentVal)) {
Slog.i(LOG_TAG, "Set ro.organization_owned property to " + value);
+ mInjector.systemPropertiesSet(PROPERTY_ORGANIZATION_OWNED, value);
+ } else if (!value.equals(currentVal)) {
+ Slog.w(LOG_TAG, "Cannot change existing ro.organization_owned to " + value);
}
}
private void maybeStartSecurityLogMonitorOnActivityManagerReady() {
synchronized (getLockObject()) {
if (mInjector.securityLogIsLoggingEnabled()) {
- mSecurityLogMonitor.start();
+ mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
mInjector.runCryptoSelfTest();
maybePauseDeviceWideLoggingLocked();
}
@@ -8396,7 +8397,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mOwners.setDeviceOwner(admin, ownerName, userId);
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
- setDeviceOwnerSystemPropertyLocked();
+ setDeviceOwnershipSystemPropertyLocked();
mInjector.binderWithCleanCallingIdentity(() -> {
// Restrict adding a managed profile when a device owner is set on the device.
@@ -9076,21 +9077,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return getApplicationLabel(profileOwner.getPackageName(), userHandle);
}
+ private @UserIdInt int getOrganizationOwnedProfileUserId() {
+ for (UserInfo ui : mUserManagerInternal.getUserInfos()) {
+ if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
+ return ui.id;
+ }
+ }
+ return UserHandle.USER_NULL;
+ }
+
@Override
public boolean isOrganizationOwnedDeviceWithManagedProfile() {
if (!mHasFeature) {
return false;
}
-
- return mInjector.binderWithCleanCallingIdentity(() -> {
- for (UserInfo ui : mUserManager.getUsers()) {
- if (ui.isManagedProfile() && isProfileOwnerOfOrganizationOwnedDevice(ui.id)) {
- return true;
- }
- }
-
- return false;
- });
+ return getOrganizationOwnedProfileUserId() != UserHandle.USER_NULL;
}
@Override
@@ -11175,6 +11176,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderRestoreCallingIdentity(id);
}
}
+ if (uninstallBlocked) {
+ final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ pmi.removeNonSystemPackageSuspensions(packageName, userId);
+ pmi.removeDistractingPackageRestrictions(packageName, userId);
+ pmi.flushPackageRestrictions(userId);
+ }
final boolean isDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED)
@@ -11703,17 +11710,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void requestSetLocationProviderAllowed(ComponentName who, String provider,
- boolean providerAllowed) {
- Objects.requireNonNull(who, "ComponentName is null");
- enforceDeviceOwner(who);
-
- mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider,
- providerAllowed));
- }
-
- @Override
public boolean setTime(ComponentName who, long millis) {
Objects.requireNonNull(who, "ComponentName is null in setTime");
enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
@@ -12062,7 +12058,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
// Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
// is delayed until device is marked as provisioned.
- setDeviceOwnerSystemPropertyLocked();
+ setDeviceOwnershipSystemPropertyLocked();
}
} else if (mDefaultImeChanged.equals(uri)) {
synchronized (getLockObject()) {
@@ -13687,6 +13683,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
}
+ private boolean canStartSecurityLogging() {
+ synchronized (getLockObject()) {
+ return isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked();
+ }
+ }
+
+ private @UserIdInt int getSecurityLoggingEnabledUser() {
+ synchronized (getLockObject()) {
+ if (mOwners.hasDeviceOwner()) {
+ return UserHandle.USER_ALL;
+ }
+ }
+ return getOrganizationOwnedProfileUserId();
+ }
+
@Override
public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) {
if (!mHasFeature) {
@@ -13695,13 +13707,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(admin);
synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(admin,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
return;
}
mInjector.securityLogSetLoggingEnabledProperty(enabled);
if (enabled) {
- mSecurityLogMonitor.start();
+ mSecurityLogMonitor.start(getSecurityLoggingEnabledUser());
maybePauseDeviceWideLoggingLocked();
} else {
mSecurityLogMonitor.stop();
@@ -13723,7 +13736,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
if (!isCallerWithSystemUid()) {
Objects.requireNonNull(admin);
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(admin,
+ DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
}
return mInjector.securityLogGetLoggingEnabledProperty();
}
@@ -13747,7 +13761,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(admin);
- ensureDeviceOwnerAndAllUsersAffiliated(admin);
+ enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+ if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+ ensureAllUsersAffiliated();
+ }
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.RETRIEVE_PRE_REBOOT_SECURITY_LOGS)
@@ -13763,6 +13780,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>();
try {
SecurityLog.readPreviousEvents(output);
+ int enabledUser = getSecurityLoggingEnabledUser();
+ if (enabledUser != UserHandle.USER_ALL) {
+ SecurityLog.redactEvents(output, enabledUser);
+ }
return new ParceledListSlice<SecurityEvent>(output);
} catch (IOException e) {
Slog.w(LOG_TAG, "Fail to read previous events" , e);
@@ -13777,7 +13798,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(admin);
- ensureDeviceOwnerAndAllUsersAffiliated(admin);
+ enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
+ if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+ ensureAllUsersAffiliated();
+ }
if (!mInjector.securityLogGetLoggingEnabledProperty()) {
return null;
@@ -14303,26 +14327,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@GuardedBy("getLockObject()")
private void maybePauseDeviceWideLoggingLocked() {
if (!areAllUsersAffiliatedWithDeviceLocked()) {
- Slog.i(LOG_TAG, "There are unaffiliated users, security and network logging will be "
+ Slog.i(LOG_TAG, "There are unaffiliated users, network logging will be "
+ "paused if enabled.");
- mSecurityLogMonitor.pause();
if (mNetworkLogger != null) {
mNetworkLogger.pause();
}
+ if (!isOrganizationOwnedDeviceWithManagedProfile()) {
+ Slog.i(LOG_TAG, "Not org-owned managed profile device, security logging will be "
+ + "paused if enabled.");
+ mSecurityLogMonitor.pause();
+ }
}
}
/** Resumes security and network logging (if they are enabled) if all users are affiliated */
@GuardedBy("getLockObject()")
private void maybeResumeDeviceWideLoggingLocked() {
- if (areAllUsersAffiliatedWithDeviceLocked()) {
- mInjector.binderWithCleanCallingIdentity(() -> {
+ boolean allUsersAffiliated = areAllUsersAffiliatedWithDeviceLocked();
+ boolean orgOwnedProfileDevice = isOrganizationOwnedDeviceWithManagedProfile();
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ if (allUsersAffiliated || orgOwnedProfileDevice) {
mSecurityLogMonitor.resume();
+ }
+ if (allUsersAffiliated) {
if (mNetworkLogger != null) {
mNetworkLogger.resume();
}
- });
- }
+ }
+ });
}
/** Deletes any security and network logs that might have been collected so far */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 1ab3b98ae78d..3c445ca78520 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -51,15 +51,17 @@ class SecurityLogMonitor implements Runnable {
private final Lock mLock = new ReentrantLock();
+ private int mEnabledUser;
+
SecurityLogMonitor(DevicePolicyManagerService service) {
this(service, 0 /* id */);
}
@VisibleForTesting
SecurityLogMonitor(DevicePolicyManagerService service, long id) {
- this.mService = service;
- this.mId = id;
- this.mLastForceNanos = System.nanoTime();
+ mService = service;
+ mId = id;
+ mLastForceNanos = System.nanoTime();
}
private static final boolean DEBUG = false; // STOPSHIP if true.
@@ -136,8 +138,15 @@ class SecurityLogMonitor implements Runnable {
@GuardedBy("mForceSemaphore")
private long mLastForceNanos = 0;
- void start() {
- Slog.i(TAG, "Starting security logging.");
+ /**
+ * Start security logging.
+ *
+ * @param enabledUser which user logging is enabled on, or USER_ALL to enable logging for all
+ * users on the device.
+ */
+ void start(int enabledUser) {
+ Slog.i(TAG, "Starting security logging for user " + enabledUser);
+ mEnabledUser = enabledUser;
SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
mLock.lock();
try {
@@ -286,7 +295,7 @@ class SecurityLogMonitor implements Runnable {
break;
}
}
-
+ SecurityLog.redactEvents(newLogs, mEnabledUser);
if (DEBUG) Slog.d(TAG, "Got " + newLogs.size() + " new events.");
}
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 859cdf24bc7e..41bc3611e085 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -274,6 +274,10 @@ public class ConversationInfo {
}
protoOutputStream.write(ConversationInfoProto.SHORTCUT_FLAGS, mShortcutFlags);
protoOutputStream.write(ConversationInfoProto.CONVERSATION_FLAGS, mConversationFlags);
+ if (mContactPhoneNumber != null) {
+ protoOutputStream.write(ConversationInfoProto.CONTACT_PHONE_NUMBER,
+ mContactPhoneNumber);
+ }
}
/** Reads from {@link ProtoInputStream} and constructs a {@link ConversationInfo}. */
@@ -315,6 +319,10 @@ public class ConversationInfo {
builder.setConversationFlags(protoInputStream.readInt(
ConversationInfoProto.CONVERSATION_FLAGS));
break;
+ case (int) ConversationInfoProto.CONTACT_PHONE_NUMBER:
+ builder.setContactPhoneNumber(protoInputStream.readString(
+ ConversationInfoProto.CONTACT_PHONE_NUMBER));
+ break;
default:
Slog.w(TAG, "Could not read undefined field: "
+ protoInputStream.getFieldNumber());
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 62e9da83869c..89c4972c8ef4 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.content.LocusId;
import android.net.Uri;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
@@ -71,16 +70,13 @@ class ConversationStore {
private final ScheduledExecutorService mScheduledExecutorService;
private final File mPackageDir;
- private final ContactsQueryHelper mHelper;
private ConversationInfosProtoDiskReadWriter mConversationInfosProtoDiskReadWriter;
ConversationStore(@NonNull File packageDir,
- @NonNull ScheduledExecutorService scheduledExecutorService,
- @NonNull ContactsQueryHelper helper) {
+ @NonNull ScheduledExecutorService scheduledExecutorService) {
mScheduledExecutorService = scheduledExecutorService;
mPackageDir = packageDir;
- mHelper = helper;
}
/**
@@ -102,7 +98,6 @@ class ConversationStore {
return;
}
for (ConversationInfo conversationInfo : conversationsOnDisk) {
- conversationInfo = restoreConversationPhoneNumber(conversationInfo);
updateConversationsInMemory(conversationInfo);
}
}
@@ -250,25 +245,6 @@ class ConversationStore {
return mConversationInfosProtoDiskReadWriter;
}
- /**
- * Conversation's phone number is not saved on disk, so it has to be fetched.
- */
- @WorkerThread
- private ConversationInfo restoreConversationPhoneNumber(
- @NonNull ConversationInfo conversationInfo) {
- if (conversationInfo.getContactUri() != null) {
- if (mHelper.query(conversationInfo.getContactUri().toString())) {
- String phoneNumber = mHelper.getPhoneNumber();
- if (!TextUtils.isEmpty(phoneNumber)) {
- conversationInfo = new ConversationInfo.Builder(
- conversationInfo).setContactPhoneNumber(
- phoneNumber).build();
- }
- }
- }
- return conversationInfo;
- }
-
/** Reads and writes {@link ConversationInfo}s on disk. */
private static class ConversationInfosProtoDiskReadWriter extends
AbstractProtoDiskReadWriter<List<ConversationInfo>> {
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 27c169227637..3a34c6a6be95 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -31,7 +31,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
@@ -53,6 +55,7 @@ import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.text.format.DateUtils;
import android.util.ArraySet;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,11 +64,13 @@ import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.SmsApplication;
import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -80,8 +85,8 @@ import java.util.function.Function;
*/
public class DataManager {
- private static final int MY_UID = Process.myUid();
- private static final int MY_PID = Process.myPid();
+ private static final String TAG = "DataManager";
+
private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
@@ -102,6 +107,7 @@ public class DataManager {
private ShortcutServiceInternal mShortcutServiceInternal;
private PackageManagerInternal mPackageManagerInternal;
+ private NotificationManagerInternal mNotificationManagerInternal;
private UserManager mUserManager;
public DataManager(Context context) {
@@ -120,9 +126,10 @@ public class DataManager {
public void initialize() {
mShortcutServiceInternal = LocalServices.getService(ShortcutServiceInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mNotificationManagerInternal = LocalServices.getService(NotificationManagerInternal.class);
mUserManager = mContext.getSystemService(UserManager.class);
- mShortcutServiceInternal.addListener(new ShortcutServiceListener());
+ mShortcutServiceInternal.addShortcutChangeCallback(new ShortcutServiceCallback());
IntentFilter shutdownIntentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
BroadcastReceiver shutdownBroadcastReceiver = new ShutdownBroadcastReceiver();
@@ -133,8 +140,7 @@ public class DataManager {
public void onUserUnlocked(int userId) {
UserData userData = mUserDataArray.get(userId);
if (userData == null) {
- userData = new UserData(userId, mDiskReadWriterExecutor,
- mInjector.createContactsQueryHelper(mContext));
+ userData = new UserData(userId, mDiskReadWriterExecutor);
mUserDataArray.put(userId, userData);
}
userData.setUserUnlocked();
@@ -363,7 +369,7 @@ public class DataManager {
return mShortcutServiceInternal.getShortcuts(
UserHandle.USER_SYSTEM, mContext.getPackageName(),
/*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
- /*componentName=*/ null, queryFlags, userId, MY_PID, MY_UID);
+ /*componentName=*/ null, queryFlags, userId, Process.myPid(), Process.myUid());
}
private void forAllUnlockedUsers(Consumer<UserData> consumer) {
@@ -622,14 +628,12 @@ public class DataManager {
}
/** Listener for the shortcut data changes. */
- private class ShortcutServiceListener implements
- ShortcutServiceInternal.ShortcutChangeListener {
+ private class ShortcutServiceCallback implements LauncherApps.ShortcutChangeCallback {
@Override
- public void onShortcutChanged(@NonNull String packageName, int userId) {
- BackgroundThread.getExecutor().execute(() -> {
- List<ShortcutInfo> shortcuts = getShortcuts(packageName, userId,
- /*shortcutIds=*/ null);
+ public void onShortcutsAddedOrUpdated(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+ mInjector.getBackgroundExecutor().execute(() -> {
for (ShortcutInfo shortcut : shortcuts) {
if (isPersonShortcut(shortcut)) {
addOrUpdateConversationInfo(shortcut);
@@ -637,6 +641,30 @@ public class DataManager {
}
});
}
+
+ @Override
+ public void onShortcutsRemoved(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
+ mInjector.getBackgroundExecutor().execute(() -> {
+ int uid = Process.INVALID_UID;
+ try {
+ uid = mContext.getPackageManager().getPackageUidAsUser(
+ packageName, user.getIdentifier());
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "Package not found: " + packageName, e);
+ }
+ PackageData packageData = getPackage(packageName, user.getIdentifier());
+ for (ShortcutInfo shortcutInfo : shortcuts) {
+ if (packageData != null) {
+ packageData.deleteDataForConversation(shortcutInfo.getId());
+ }
+ if (uid != Process.INVALID_UID) {
+ mNotificationManagerInternal.onConversationRemoved(
+ shortcutInfo.getPackage(), uid, shortcutInfo.getId());
+ }
+ }
+ });
+ }
}
/** Listener for the notifications and their settings changes. */
@@ -789,6 +817,10 @@ public class DataManager {
return Executors.newSingleThreadScheduledExecutor();
}
+ Executor getBackgroundExecutor() {
+ return BackgroundThread.getExecutor();
+ }
+
ContactsQueryHelper createContactsQueryHelper(Context context) {
return new ContactsQueryHelper(context);
}
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index d47e2cc1ba90..35d245fc8d10 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -59,16 +59,14 @@ public class PackageData {
@NonNull Predicate<String> isDefaultDialerPredicate,
@NonNull Predicate<String> isDefaultSmsAppPredicate,
@NonNull ScheduledExecutorService scheduledExecutorService,
- @NonNull File perUserPeopleDataDir,
- @NonNull ContactsQueryHelper helper) {
+ @NonNull File perUserPeopleDataDir) {
mPackageName = packageName;
mUserId = userId;
mPackageDataDir = new File(perUserPeopleDataDir, mPackageName);
mPackageDataDir.mkdirs();
- mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService,
- helper);
+ mConversationStore = new ConversationStore(mPackageDataDir, scheduledExecutorService);
mEventStore = new EventStore(mPackageDataDir, scheduledExecutorService);
mIsDefaultDialerPredicate = isDefaultDialerPredicate;
mIsDefaultSmsAppPredicate = isDefaultSmsAppPredicate;
@@ -83,8 +81,7 @@ public class PackageData {
@NonNull Predicate<String> isDefaultDialerPredicate,
@NonNull Predicate<String> isDefaultSmsAppPredicate,
@NonNull ScheduledExecutorService scheduledExecutorService,
- @NonNull File perUserPeopleDataDir,
- @NonNull ContactsQueryHelper helper) {
+ @NonNull File perUserPeopleDataDir) {
Map<String, PackageData> results = new ArrayMap<>();
File[] packageDirs = perUserPeopleDataDir.listFiles(File::isDirectory);
if (packageDirs == null) {
@@ -93,7 +90,7 @@ public class PackageData {
for (File packageDir : packageDirs) {
PackageData packageData = new PackageData(packageDir.getName(), userId,
isDefaultDialerPredicate, isDefaultSmsAppPredicate, scheduledExecutorService,
- perUserPeopleDataDir, helper);
+ perUserPeopleDataDir);
packageData.loadFromDisk();
results.put(packageDir.getName(), packageData);
}
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index d3cecceed884..0f8b91bfa2b1 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -37,8 +37,6 @@ class UserData {
private final ScheduledExecutorService mScheduledExecutorService;
- private final ContactsQueryHelper mHelper;
-
private boolean mIsUnlocked;
private Map<String, PackageData> mPackageDataMap = new ArrayMap<>();
@@ -49,12 +47,10 @@ class UserData {
@Nullable
private String mDefaultSmsApp;
- UserData(@UserIdInt int userId, @NonNull ScheduledExecutorService scheduledExecutorService,
- ContactsQueryHelper helper) {
+ UserData(@UserIdInt int userId, @NonNull ScheduledExecutorService scheduledExecutorService) {
mUserId = userId;
mPerUserPeopleDataDir = new File(Environment.getDataSystemCeDirectory(mUserId), "people");
mScheduledExecutorService = scheduledExecutorService;
- mHelper = helper;
}
@UserIdInt int getUserId() {
@@ -74,7 +70,7 @@ class UserData {
// data from disk.
mPerUserPeopleDataDir.mkdirs();
mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
- this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir, mHelper));
+ this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir));
}
void setUserStopped() {
@@ -131,7 +127,7 @@ class UserData {
private PackageData createPackageData(String packageName) {
return new PackageData(packageName, mUserId, this::isDefaultDialer, this::isDefaultSmsApp,
- mScheduledExecutorService, mPerUserPeopleDataDir, mHelper);
+ mScheduledExecutorService, mPerUserPeopleDataDir);
}
private boolean isDefaultDialer(String packageName) {
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 62ff3a1c2126..ec56e1ebc8e0 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,7 +96,6 @@ 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;
@@ -259,9 +258,6 @@ 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
@@ -2348,9 +2344,6 @@ 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);
@@ -2368,9 +2361,6 @@ 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/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 1c8b00f303d9..30bb38a075be 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -111,6 +111,29 @@ public class AuthServiceTest {
any());
}
+ @Test
+ public void testRegisterAuthenticator_callsInitConfiguredStrength() throws Exception {
+
+ final String[] config = {
+ "0:2:15", // ID0:Fingerprint:Strong
+ "1:4:255", // ID1:Iris:Weak
+ "2:8:4095", // ID2:Face:Convenience
+ };
+
+ when(mInjector.getConfiguration(any())).thenReturn(config);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final int fingerprintStrength = 15;
+ final int irisStrength = 255;
+ final int faceStrength = 4095;
+
+ verify(mFingerprintService).initConfiguredStrength(eq(fingerprintStrength));
+ verify(mIrisService).initConfiguredStrength(eq(irisStrength));
+ verify(mFaceService).initConfiguredStrength(eq(faceStrength));
+ }
+
// TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId
@Test
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 dbf2f14146fb..ac818ea8385f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3952,13 +3952,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
public void testIsOrganizationOwnedDevice() throws Exception {
- setupProfileOwner();
// Set up the user manager to return correct user info
- UserInfo managedProfileUserInfo = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
- "managed profile",
- UserInfo.FLAG_MANAGED_PROFILE);
- when(getServices().userManager.getUsers())
- .thenReturn(Arrays.asList(managedProfileUserInfo));
+ addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1);
// Any caller should be able to call this method.
assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile());
@@ -5909,8 +5904,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
- when(getServices().userManager.getProfileParent(eq(UserHandle.of(userId))))
- .thenReturn(UserHandle.SYSTEM);
final long ident = mServiceContext.binder.clearCallingIdentity();
mServiceContext.binder.callingUid = UserHandle.getUid(userId, DpmMockContext.SYSTEM_UID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 37d40811571f..01f1a3e92f2c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -265,6 +265,9 @@ public class MockSystemServices {
.toArray();
}
);
+ when(userManagerInternal.getUserInfos()).thenReturn(
+ mUserInfos.toArray(new UserInfo[mUserInfos.size()]));
+
when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
// Create a data directory.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
index 0f0521298641..8dcf21f9fe77 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java
@@ -1,31 +1,43 @@
package com.android.server.devicepolicy;
import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD;
+import static android.app.admin.SecurityLog.TAG_APP_PROCESS_START;
+import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED;
+import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED;
+import static android.app.admin.SecurityLog.TAG_KEY_DESTRUCTION;
+import static android.app.admin.SecurityLog.TAG_KEY_GENERATED;
+import static android.app.admin.SecurityLog.TAG_KEY_IMPORT;
+import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION;
+import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT;
+import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT;
import android.app.admin.SecurityLog.SecurityEvent;
import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.EventLog;
+import android.util.EventLog.Event;
+
+import junit.framework.AssertionFailedError;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-@SmallTest
public class SecurityEventTest extends DpmTestBase {
- private static long ID = 549;
- private static String DATA = "adb shell some_command";
- public void testSecurityEventId() {
- SecurityEvent event = buildSecurityEvents(1 /* generate a single event */, ID).get(0);
- assertEquals(ID, event.getId());
+ public void testSecurityEventId() throws Exception {
+ SecurityEvent event = createEvent(() -> {
+ EventLog.writeEvent(TAG_ADB_SHELL_CMD, 0);
+ }, TAG_ADB_SHELL_CMD);
event.setId(20);
assertEquals(20, event.getId());
}
- public void testSecurityEventParceling() {
+ public void testSecurityEventParceling() throws Exception {
// GIVEN an event.
- SecurityEvent event = buildSecurityEvents(1 /* generate a single event */, ID).get(0);
+ SecurityEvent event = createEvent(() -> {
+ EventLog.writeEvent(TAG_ADB_SHELL_CMD, "test");
+ }, TAG_ADB_SHELL_CMD);
// WHEN parceling the event.
Parcel p = Parcel.obtain();
p.writeParcelable(event, 0);
@@ -39,23 +51,104 @@ public class SecurityEventTest extends DpmTestBase {
assertEquals(event.getId(), unparceledEvent.getId());
}
- private List<SecurityEvent> buildSecurityEvents(int numEvents, long id) {
- // Write an event to the EventLog.
- for (int i = 0; i < numEvents; i++) {
- EventLog.writeEvent(TAG_ADB_SHELL_CMD, DATA + "_" + i);
- }
- List<EventLog.Event> events = new ArrayList<>();
- try {
- EventLog.readEvents(new int[]{TAG_ADB_SHELL_CMD}, events);
- } catch (IOException e) {
- fail("Reading a test event from storage failed: " + e);
- }
- assertTrue("Unexpected number of events read from the log.", events.size() >= numEvents);
- // Read events generated by test, from the end of the log.
- List<SecurityEvent> securityEvents = new ArrayList<>();
- for (int i = events.size() - numEvents; i < events.size(); i++) {
- securityEvents.add(new SecurityEvent(id++, events.get(i).getBytes()));
+ public void testSecurityEventRedaction() throws Exception {
+ SecurityEvent event;
+
+ // TAG_ADB_SHELL_CMD will has the command redacted
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_ADB_SHELL_CMD, "command");
+ }, TAG_ADB_SHELL_CMD);
+ assertFalse(TextUtils.isEmpty((String) event.getData()));
+
+ // TAG_MEDIA_MOUNT will have the volume label redacted (second data)
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_MEDIA_MOUNT, new Object[] {"path", "label"});
+ }, TAG_MEDIA_MOUNT);
+ assertFalse(TextUtils.isEmpty(event.getStringData(1)));
+ assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1)));
+
+ // TAG_MEDIA_UNMOUNT will have the volume label redacted (second data)
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_MEDIA_UNMOUNT, new Object[] {"path", "label"});
+ }, TAG_MEDIA_UNMOUNT);
+ assertFalse(TextUtils.isEmpty(event.getStringData(1)));
+ assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1)));
+
+ // TAG_APP_PROCESS_START will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_APP_PROCESS_START, new Object[] {"process", 12345L,
+ UserHandle.getUid(10, 123), 456, "seinfo", "hash"});
+ }, TAG_APP_PROCESS_START);
+ assertNotNull(event.redact(10));
+ assertNull(event.redact(11));
+
+ // TAG_CERT_AUTHORITY_INSTALLED will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_CERT_AUTHORITY_INSTALLED, new Object[] {1, "subject", 10});
+ }, TAG_CERT_AUTHORITY_INSTALLED);
+ assertNotNull(event.redact(10));
+ assertNull(event.redact(11));
+
+ // TAG_CERT_AUTHORITY_REMOVED will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_CERT_AUTHORITY_REMOVED, new Object[] {1, "subject", 20});
+ }, TAG_CERT_AUTHORITY_REMOVED);
+ assertNotNull(event.redact(20));
+ assertNull(event.redact(0));
+
+ // TAG_KEY_GENERATED will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_KEY_GENERATED,
+ new Object[] {1, "alias", UserHandle.getUid(0, 123)});
+ }, TAG_KEY_GENERATED);
+ assertNotNull(event.redact(0));
+ assertNull(event.redact(10));
+
+ // TAG_KEY_IMPORT will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_KEY_IMPORT,
+ new Object[] {1, "alias", UserHandle.getUid(1, 123)});
+ }, TAG_KEY_IMPORT);
+ assertNotNull(event.redact(1));
+ assertNull(event.redact(10));
+
+ // TAG_KEY_DESTRUCTION will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_KEY_DESTRUCTION,
+ new Object[] {1, "alias", UserHandle.getUid(2, 123)});
+ }, TAG_KEY_DESTRUCTION);
+ assertNotNull(event.redact(2));
+ assertNull(event.redact(10));
+
+ // TAG_KEY_INTEGRITY_VIOLATION will be fully redacted if user does not match
+ event = createEvent(() -> {
+ EventLog.writeEvent(TAG_KEY_INTEGRITY_VIOLATION,
+ new Object[] {"alias", UserHandle.getUid(2, 123)});
+ }, TAG_KEY_INTEGRITY_VIOLATION);
+ assertNotNull(event.redact(2));
+ assertNull(event.redact(10));
+
+ }
+
+ /**
+ * Creates an Event object. Only the native code has the serialization and deserialization logic
+ * so need to actually emit a real log in order to generate the object.
+ */
+ private SecurityEvent createEvent(Runnable generator, int expectedTag) throws Exception {
+ Long markerData = System.currentTimeMillis();
+ EventLog.writeEvent(expectedTag, markerData);
+ generator.run();
+
+ List<Event> events = new ArrayList<>();
+ // Give the message some time to show up in the log
+ Thread.sleep(20);
+ EventLog.readEvents(new int[] {expectedTag}, events);
+
+ for (int i = 0; i < events.size() - 1; i++) {
+ if (markerData.equals(events.get(i).getData())) {
+ return new SecurityEvent(0, events.get(i + 1).getBytes());
+ }
}
- return securityEvents;
+ throw new AssertionFailedError("Unable to locate marker event");
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 25d077823a3f..feae1e173f52 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -29,6 +29,12 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
+import com.android.server.display.DisplayModeDirector.RefreshRateRange;
+import com.android.server.display.DisplayModeDirector.Vote;
+
+import com.google.common.truth.Truth;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,6 +43,9 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayModeDirectorTest {
+ // The tolerance within which we consider something approximately equals.
+ private static final float FLOAT_TOLERANCE = 0.01f;
+
private Context mContext;
@Before
@@ -56,30 +65,22 @@ public class DisplayModeDirectorTest {
modes[i - minFps] = new Display.Mode(
/*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
}
- SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
supportedModesByDisplay.put(displayId, modes);
director.injectSupportedModesByDisplay(supportedModesByDisplay);
- SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+ SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
defaultModesByDisplay.put(displayId, modes[0]);
director.injectDefaultModeByDisplay(defaultModesByDisplay);
return director;
}
- private int[] intRange(int min, int max) {
- int[] range = new int[max - min + 1];
- for (int i = min; i <= max; i++) {
- range[i - min] = i;
- }
- return range;
- }
-
@Test
public void testDisplayModeVoting() {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60,
- new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
+ assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/60,
+ new RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
displayId));
@@ -93,20 +94,16 @@ public class DisplayModeDirectorTest {
int maxFps = 90;
DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
assertTrue(2 * numPriorities < maxFps - minFps + 1);
- SparseArray<DisplayModeDirector.Vote> votes =
- new SparseArray<DisplayModeDirector.Vote>();
- SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
- new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
for (int i = 0; i < numPriorities; i++) {
- int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
- votes.put(
- priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+ int priority = Vote.MIN_PRIORITY + i;
+ votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(
- new DisplayModeDirector.DesiredDisplayModeSpecs(
+ assertEquals(new DesiredDisplayModeSpecs(
/*baseModeId=*/minFps + i,
- new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)),
+ new RefreshRateRange(minFps + i, maxFps - i)),
director.getDesiredDisplayModeSpecs(displayId));
}
}
@@ -116,19 +113,35 @@ public class DisplayModeDirectorTest {
{
assertTrue(numPriorities >= 2);
DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
- SparseArray<DisplayModeDirector.Vote> votes =
- new SparseArray<DisplayModeDirector.Vote>();
- SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
- new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
- votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
- DisplayModeDirector.Vote.forRefreshRates(65, 85));
- votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
- DisplayModeDirector.Vote.forRefreshRates(70, 80));
+ votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
+ votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70,
- new DisplayModeDirector.RefreshRateRange(70, 80)),
+ assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/70,
+ new RefreshRateRange(70, 80)),
director.getDesiredDisplayModeSpecs(displayId));
}
}
+
+ @Test
+ public void testVotingWithFloatingPointErrors() {
+ int displayId = 0;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(50, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(displayId, votes);
+ float error = FLOAT_TOLERANCE / 4;
+ votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
+ votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
+ Vote.forRefreshRates(60 - error, 60 - error));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+
+ Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
index 6fafe113d90d..9b076e8edb52 100644
--- a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java
@@ -118,16 +118,6 @@ public class MockableLocationProviderTest {
}
@Test
- public void testRequestSetAllowed() {
- mProvider.requestSetAllowed(true);
- verify(mRealProvider, times(1)).onRequestSetAllowed(true);
-
- mProvider.setMockProvider(mMockProvider);
- mProvider.requestSetAllowed(true);
- verify(mMockProvider, times(1)).onRequestSetAllowed(true);
- }
-
- @Test
public void testSendExtraCommand() {
mProvider.sendExtraCommand(0, 0, "command", null);
verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null);
diff --git a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
index 762080fe5745..5943f67494f8 100644
--- a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java
@@ -38,8 +38,5 @@ public class FakeProvider extends AbstractLocationProvider {
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
- protected void onRequestSetAllowed(boolean allowed) {}
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index 03b5e38cadb7..d138700f1d2a 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.LocusId;
import android.content.pm.ShortcutInfo;
@@ -63,7 +62,6 @@ public final class ConversationStoreTest {
private static final String PHONE_NUMBER_3 = "+9234567890";
private MockScheduledExecutorService mMockScheduledExecutorService;
- private TestContactQueryHelper mTestContactQueryHelper;
private ConversationStore mConversationStore;
private File mFile;
@@ -71,7 +69,6 @@ public final class ConversationStoreTest {
public void setUp() {
Context ctx = InstrumentationRegistry.getContext();
mFile = new File(ctx.getCacheDir(), "testdir");
- mTestContactQueryHelper = new TestContactQueryHelper(ctx);
resetConversationStore();
}
@@ -207,9 +204,6 @@ public final class ConversationStoreTest {
mConversationStore.deleteConversation(SHORTCUT_ID_3);
mMockScheduledExecutorService.fastForwardTime(3L * DateUtils.MINUTE_IN_MILLIS);
- mTestContactQueryHelper.setQueryResult(true, true);
- mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2);
-
resetConversationStore();
ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -240,9 +234,6 @@ public final class ConversationStoreTest {
mConversationStore.addOrUpdate(in2);
mMockScheduledExecutorService.fastForwardTime(DateUtils.MINUTE_IN_MILLIS);
- mTestContactQueryHelper.setQueryResult(true);
- mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER);
-
resetConversationStore();
ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -256,10 +247,6 @@ public final class ConversationStoreTest {
mConversationStore.addOrUpdate(in3);
mMockScheduledExecutorService.fastForwardTime(3L * DateUtils.MINUTE_IN_MILLIS);
- mTestContactQueryHelper.reset();
- mTestContactQueryHelper.setQueryResult(true, true, true);
- mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2, PHONE_NUMBER_3);
-
resetConversationStore();
out1 = mConversationStore.getConversation(SHORTCUT_ID);
out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -290,9 +277,6 @@ public final class ConversationStoreTest {
// loadConversationFromDisk gets called each time we call #resetConversationStore().
assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
- mTestContactQueryHelper.setQueryResult(true, true);
- mTestContactQueryHelper.setPhoneNumberResult(PHONE_NUMBER, PHONE_NUMBER_2);
-
resetConversationStore();
ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
ConversationInfo out2 = mConversationStore.getConversation(SHORTCUT_ID_2);
@@ -303,8 +287,7 @@ public final class ConversationStoreTest {
private void resetConversationStore() {
mFile.mkdir();
mMockScheduledExecutorService = new MockScheduledExecutorService();
- mConversationStore = new ConversationStore(mFile, mMockScheduledExecutorService,
- mTestContactQueryHelper);
+ mConversationStore = new ConversationStore(mFile, mMockScheduledExecutorService);
mConversationStore.loadConversationsFromDisk();
}
@@ -326,54 +309,4 @@ public final class ConversationStoreTest {
.setBubbled(true)
.build();
}
-
- private static class TestContactQueryHelper extends ContactsQueryHelper {
-
- private int mQueryCalls;
- private boolean[] mQueryResult;
-
- private int mPhoneNumberCalls;
- private String[] mPhoneNumberResult;
-
- TestContactQueryHelper(Context context) {
- super(context);
-
- mQueryCalls = 0;
- mPhoneNumberCalls = 0;
- }
-
- private void setQueryResult(boolean... values) {
- mQueryResult = values;
- }
-
- private void setPhoneNumberResult(String... values) {
- mPhoneNumberResult = values;
- }
-
- private void reset() {
- mQueryCalls = 0;
- mQueryResult = null;
- mPhoneNumberCalls = 0;
- mPhoneNumberResult = null;
- }
-
- @Override
- boolean query(String contactUri) {
- if (mQueryResult != null && mQueryCalls < mQueryResult.length) {
- return mQueryResult[mQueryCalls++];
- }
- mQueryCalls++;
- return false;
- }
-
- @Override
- @Nullable
- String getPhoneNumber() {
- if (mPhoneNumberResult != null && mPhoneNumberCalls < mPhoneNumberResult.length) {
- return mPhoneNumberResult[mPhoneNumberCalls++];
- }
- mPhoneNumberCalls++;
- return null;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index b54317b768c5..f0b7d206f2bf 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -52,6 +52,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.LauncherApps.ShortcutChangeCallback;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
@@ -72,6 +74,7 @@ import android.util.Range;
import com.android.internal.app.ChooserActivity;
import com.android.internal.content.PackageMonitor;
import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import org.junit.After;
@@ -79,6 +82,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -87,6 +92,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -102,6 +108,7 @@ public final class DataManagerTest {
private static final String TEST_PKG_NAME = "pkg";
private static final String TEST_CLASS_NAME = "class";
private static final String TEST_SHORTCUT_ID = "sc";
+ private static final int TEST_PKG_UID = 35;
private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
private static final String PHONE_NUMBER = "+1234567890";
private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
@@ -111,7 +118,9 @@ public final class DataManagerTest {
@Mock private ShortcutServiceInternal mShortcutServiceInternal;
@Mock private UsageStatsManagerInternal mUsageStatsManagerInternal;
@Mock private PackageManagerInternal mPackageManagerInternal;
+ @Mock private NotificationManagerInternal mNotificationManagerInternal;
@Mock private UserManager mUserManager;
+ @Mock private PackageManager mPackageManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private TelecomManager mTelecomManager;
@Mock private ContentResolver mContentResolver;
@@ -121,13 +130,16 @@ public final class DataManagerTest {
@Mock private StatusBarNotification mStatusBarNotification;
@Mock private Notification mNotification;
+ @Captor private ArgumentCaptor<ShortcutChangeCallback> mShortcutChangeCallbackCaptor;
+
private NotificationChannel mNotificationChannel;
private DataManager mDataManager;
private CancellationSignal mCancellationSignal;
+ private ShortcutChangeCallback mShortcutChangeCallback;
private TestInjector mInjector;
@Before
- public void setUp() {
+ public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
addLocalServiceMock(ShortcutServiceInternal.class, mShortcutServiceInternal);
@@ -143,8 +155,12 @@ public final class DataManagerTest {
return null;
}).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
+ addLocalServiceMock(NotificationManagerInternal.class, mNotificationManagerInternal);
+
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
when(mContext.getPackageName()).thenReturn("android");
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
Context originalContext = getInstrumentation().getTargetContext();
when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
@@ -175,7 +191,8 @@ public final class DataManagerTest {
when(mUserManager.getEnabledProfiles(USER_ID_SECONDARY))
.thenReturn(Collections.singletonList(buildUserInfo(USER_ID_SECONDARY)));
- when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mPackageManager.getPackageUidAsUser(TEST_PKG_NAME, USER_ID_PRIMARY))
+ .thenReturn(TEST_PKG_UID);
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
when(mStatusBarNotification.getPackageName()).thenReturn(TEST_PKG_NAME);
@@ -192,6 +209,10 @@ public final class DataManagerTest {
mInjector = new TestInjector();
mDataManager = new DataManager(mContext, mInjector);
mDataManager.initialize();
+
+ verify(mShortcutServiceInternal).addShortcutChangeCallback(
+ mShortcutChangeCallbackCaptor.capture());
+ mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
}
@After
@@ -474,6 +495,43 @@ public final class DataManagerTest {
}
@Test
+ public void testShortcutAddedOrUpdated() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
+ Collections.singletonList(shortcut), UserHandle.of(USER_ID_PRIMARY));
+
+ List<ConversationInfo> conversations = getConversationsInPrimary();
+
+ assertEquals(1, conversations.size());
+ assertEquals(TEST_SHORTCUT_ID, conversations.get(0).getShortcutId());
+ }
+
+ @Test
+ public void testShortcutDeleted() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc1",
+ buildPerson());
+ ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc2",
+ buildPerson());
+ mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
+ Arrays.asList(shortcut1, shortcut2), UserHandle.of(USER_ID_PRIMARY));
+ mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME,
+ Collections.singletonList(shortcut1), UserHandle.of(USER_ID_PRIMARY));
+
+ List<ConversationInfo> conversations = getConversationsInPrimary();
+
+ assertEquals(1, conversations.size());
+ assertEquals("sc2", conversations.get(0).getShortcutId());
+
+ verify(mNotificationManagerInternal)
+ .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, "sc1");
+ }
+
+ @Test
public void testCallLogContentObserver() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
mDataManager.onUserUnlocked(USER_ID_SECONDARY);
@@ -765,6 +823,11 @@ public final class DataManagerTest {
}
@Override
+ Executor getBackgroundExecutor() {
+ return Runnable::run;
+ }
+
+ @Override
ContactsQueryHelper createContactsQueryHelper(Context context) {
return mContactsQueryHelper;
}
diff --git a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
index e52cdf59847c..8191d17aba97 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/PackageDataTest.java
@@ -61,7 +61,7 @@ public final class PackageDataTest {
testDir.mkdir();
mPackageData = new PackageData(
PACKAGE_NAME, USER_ID, pkg -> mIsDefaultDialer, pkg -> mIsDefaultSmsApp,
- new MockScheduledExecutorService(), testDir, new ContactsQueryHelper(ctx));
+ new MockScheduledExecutorService(), testDir);
ConversationInfo conversationInfo = new ConversationInfo.Builder()
.setShortcutId(SHORTCUT_ID)
.setLocusId(LOCUS_ID)
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index 418067fd14f8..7934d33f907d 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -79,10 +79,9 @@ public final class UsageStatsQueryHelperTest {
Context ctx = InstrumentationRegistry.getContext();
File testDir = new File(ctx.getCacheDir(), "testdir");
ScheduledExecutorService scheduledExecutorService = new MockScheduledExecutorService();
- ContactsQueryHelper helper = new ContactsQueryHelper(ctx);
mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false,
- scheduledExecutorService, testDir, helper);
+ scheduledExecutorService, testDir);
mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder()
.setShortcutId(SHORTCUT_ID)
.setLocusId(LOCUS_ID_1)
@@ -221,9 +220,8 @@ public final class UsageStatsQueryHelperTest {
private ConversationInfo mConversationInfo;
TestConversationStore(File packageDir,
- ScheduledExecutorService scheduledExecutorService,
- ContactsQueryHelper helper) {
- super(packageDir, scheduledExecutorService, helper);
+ ScheduledExecutorService scheduledExecutorService) {
+ super(packageDir, scheduledExecutorService);
}
@Override
@@ -241,12 +239,10 @@ public final class UsageStatsQueryHelperTest {
TestPackageData(@NonNull String packageName, @UserIdInt int userId,
@NonNull Predicate<String> isDefaultDialerPredicate,
@NonNull Predicate<String> isDefaultSmsAppPredicate,
- @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull File rootDir,
- @NonNull ContactsQueryHelper helper) {
+ @NonNull ScheduledExecutorService scheduledExecutorService, @NonNull File rootDir) {
super(packageName, userId, isDefaultDialerPredicate, isDefaultSmsAppPredicate,
- scheduledExecutorService, rootDir, helper);
- mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService,
- helper);
+ scheduledExecutorService, rootDir);
+ mConversationStore = new TestConversationStore(rootDir, scheduledExecutorService);
mEventStore = new TestEventStore(rootDir, scheduledExecutorService);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 118c540a4131..bec37e929a80 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -812,7 +812,7 @@ public final class UserManagerTest {
"android", 0, mUserManager.getPrimaryUser().getUserHandle())
.getSystemService(Context.USER_SERVICE);
- List<UserHandle> profiles = um.getUserProfiles(false);
+ List<UserHandle> profiles = um.getAllProfiles();
assertThat(profiles.size()).isEqualTo(2);
assertThat(profiles.get(0).equals(userProfile.getUserHandle())
|| profiles.get(1).equals(userProfile.getUserHandle())).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 624cb83f9e19..9e067304fc7f 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -297,9 +297,11 @@ public class ThermalManagerServiceTest {
@Test
public void testGetCurrentTemperatures() throws RemoteException {
assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0),
- mService.mService.getCurrentTemperatures());
- assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
- mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN));
+ Arrays.asList(mService.mService.getCurrentTemperatures()));
+ assertListEqualsIgnoringOrder(
+ mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
+ Arrays.asList(mService.mService.getCurrentTemperaturesWithType(
+ Temperature.TYPE_SKIN)));
}
@Test
@@ -331,21 +333,22 @@ public class ThermalManagerServiceTest {
assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1));
assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1));
- assertEquals(0, mService.mService.getCurrentTemperatures().size());
- assertEquals(0,
- mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size());
+ assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperatures()).size());
+ assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperaturesWithType(
+ Temperature.TYPE_SKIN)).size());
assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus());
}
@Test
public void testGetCurrentCoolingDevices() throws RemoteException {
assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0),
- mService.mService.getCurrentCoolingDevices());
+ Arrays.asList(mService.mService.getCurrentCoolingDevices()));
assertListEqualsIgnoringOrder(
mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY),
- mService.mService.getCurrentCoolingDevices());
+ Arrays.asList(mService.mService.getCurrentCoolingDevices()));
assertListEqualsIgnoringOrder(
mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU),
- mService.mService.getCurrentCoolingDevicesWithType(CoolingDevice.TYPE_CPU));
+ Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType(
+ CoolingDevice.TYPE_CPU)));
}
}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 3f0cda3b8e5a..b7199f7cdd5a 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -29,6 +29,7 @@ android_test {
libs: [
"android.test.runner",
"android.test.base",
+ "android.test.mock",
],
dxflags: ["--multi-dex"],
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 ccce0436ea59..d0283f78338d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3246,7 +3246,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
false,
UserHandle.USER_ALL);
- verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class));
+ verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class), anyLong());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7f9732bb350a..58299614efe8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -36,9 +36,10 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -67,6 +68,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.ConversationChannelWrapper;
+import android.test.mock.MockIContentProvider;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
@@ -87,6 +89,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -123,7 +126,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Mock NotificationUsageStats mUsageStats;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
- @Mock IContentProvider mTestIContentProvider;
+ @Spy IContentProvider mTestIContentProvider = new MockIContentProvider();
@Mock Context mContext;
@Mock ZenModeHelper mMockZenModeHelper;
@@ -170,12 +173,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
- .thenReturn(CANONICAL_SOUND_URI);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(CANONICAL_SOUND_URI);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(SOUND_URI);
+ doReturn(CANONICAL_SOUND_URI)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
+ doReturn(CANONICAL_SOUND_URI)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(SOUND_URI)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
@@ -506,12 +509,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
.appendQueryParameter("title", "Test")
.appendQueryParameter("canonical", "1")
.build();
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(canonicalBasedOnLocal);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(localUri);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(canonicalBasedOnLocal)))
- .thenReturn(localUri);
+ doReturn(canonicalBasedOnLocal)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(localUri)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(localUri)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(),
+ eq(canonicalBasedOnLocal));
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -530,10 +534,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
Thread.sleep(3000);
- when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(null);
- when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
- .thenReturn(null);
+ doReturn(null)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
+ doReturn(null)
+ .when(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -557,7 +561,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
// Not a local uncanonicalized uri, simulating that it fails to exist locally
- when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI))).thenReturn(null);
+ doReturn(null)
+ .when(mTestIContentProvider).canonicalize(any(), any(), eq(SOUND_URI));
String id = "id";
String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 1dd0b1a6f359..816e8e57acc6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
@@ -96,10 +97,33 @@ public class SnoozeHelperTest extends UiServiceTestCase {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
- mSnoozeHelper.readXml(parser);
- assertTrue("Should read the notification time from xml and it should be more than zero",
- 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
- 0, "pkg", "key").doubleValue());
+ mSnoozeHelper.readXml(parser, 1);
+ assertEquals((long) Long.MAX_VALUE, (long) mSnoozeHelper
+ .getSnoozeTimeForUnpostedNotification(0, "pkg", "key"));
+ verify(mAm, never()).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
+ }
+
+ @Test
+ public void testWriteXML_afterReading_noNPE()
+ throws XmlPullParserException, IOException {
+ final String max_time_str = Long.toString(Long.MAX_VALUE);
+ final String xml_string = "<snoozed-notifications>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key\" time=\"" + max_time_str + "\"/>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
+ + "</snoozed-notifications>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml_string.getBytes())), null);
+ mSnoozeHelper.readXml(parser, 1);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mSnoozeHelper.writeXml(serializer);
+ serializer.endDocument();
+ serializer.flush();
}
@Test
@@ -115,7 +139,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
- mSnoozeHelper.readXml(parser);
+ mSnoozeHelper.readXml(parser, 1);
assertEquals("Should read the notification context from xml and it should be `uri",
"uri", mSnoozeHelper.getSnoozeContextForUnpostedNotification(
0, "pkg", "key"));
@@ -137,7 +161,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
- mSnoozeHelper.readXml(parser);
+ mSnoozeHelper.readXml(parser, 1);
assertTrue("Should read the notification time from xml and it should be more than zero",
0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
0, "pkg", r.getKey()).doubleValue());
@@ -161,7 +185,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
- mSnoozeHelper.readXml(parser);
+ mSnoozeHelper.readXml(parser, 2);
int systemUser = UserHandle.SYSTEM.getIdentifier();
assertTrue("Should see a past time returned",
System.currentTimeMillis() > mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
@@ -195,6 +219,30 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testScheduleRepostsForPersistedNotifications() throws Exception {
+ final String xml_string = "<snoozed-notifications>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key\" time=\"" + 10 + "\"/>"
+ + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ + "pkg=\"pkg\" key=\"key2\" time=\"" + 15+ "\"/>"
+ + "</snoozed-notifications>";
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml_string.getBytes())), null);
+ mSnoozeHelper.readXml(parser, 4);
+
+ mSnoozeHelper.scheduleRepostsForPersistedNotifications(5);
+
+ ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+ verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 10), captor.capture());
+ assertEquals("key", captor.getValue().getIntent().getStringExtra(EXTRA_KEY));
+
+ ArgumentCaptor<PendingIntent> captor2 = ArgumentCaptor.forClass(PendingIntent.class);
+ verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 15), captor2.capture());
+ assertEquals("key2", captor2.getValue().getIntent().getStringExtra(EXTRA_KEY));
+ }
+
+ @Test
public void testSnoozeForTime() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, 1000);
@@ -414,6 +462,23 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testGetSnoozedGroupNotifications_nonGrouped() throws Exception {
+ IntArray profileIds = new IntArray();
+ profileIds.add(UserHandle.USER_CURRENT);
+ when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
+ NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
+ UserHandle.CURRENT, "group", true);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
+ UserHandle.CURRENT, null, true);
+ mSnoozeHelper.snooze(r, 1000);
+ mSnoozeHelper.snooze(r2, 1000);
+
+ assertEquals(1,
+ mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size());
+ // and no NPE
+ }
+
+ @Test
public void testGetSnoozedNotificationByKey() throws Exception {
IntArray profileIds = new IntArray();
profileIds.add(UserHandle.USER_CURRENT);
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
new file mode 100644
index 000000000000..f56c2cf76956
--- /dev/null
+++ b/services/wifi/Android.bp
@@ -0,0 +1,13 @@
+filegroup {
+ name: "services.wifi-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.wifi",
+ srcs: [
+ ":services.wifi-sources",
+ ],
+}
diff --git a/services/wifi/java/com/android/server/wifi/SupplicantManager.java b/services/wifi/java/com/android/server/wifi/SupplicantManager.java
new file mode 100644
index 000000000000..5ed1ab3198e2
--- /dev/null
+++ b/services/wifi/java/com/android/server/wifi/SupplicantManager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.wifi;
+
+import android.annotation.SystemApi;
+import android.os.SystemService;
+
+/**
+ * Wrapper to start/stop supplicant daemon using init system.
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public class SupplicantManager {
+ private static final String WPA_SUPPLICANT_DAEMON_NAME = "wpa_supplicant";
+
+ private SupplicantManager() {}
+
+ /**
+ * Start the wpa_supplicant daemon.
+ * Note: This uses the init system to start the "wpa_supplicant" service.
+ */
+ public static void start() {
+ SystemService.start(WPA_SUPPLICANT_DAEMON_NAME);
+ }
+
+ /**
+ * Stop the wpa_supplicant daemon.
+ * Note: This uses the init system to stop the "wpa_supplicant" service.
+ */
+ public static void stop() {
+ SystemService.stop(WPA_SUPPLICANT_DAEMON_NAME);
+ }
+}
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index f7ec11c79476..d1d64d39b688 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -156,6 +156,12 @@ public class MockContentProvider extends ContentProvider {
}
@Override
+ public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+ RemoteCallback callback) {
+ MockContentProvider.this.canonicalizeAsync(uri, callback);
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException {
return MockContentProvider.this.uncanonicalize(uri);
@@ -292,6 +298,18 @@ public class MockContentProvider extends ContentProvider {
/**
* @hide
*/
+ @SuppressWarnings("deprecation")
+ public void canonicalizeAsync(Uri uri, RemoteCallback callback) {
+ AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(uri));
+ callback.sendResult(bundle);
+ });
+ }
+
+ /**
+ * @hide
+ */
public boolean refresh(Uri url, Bundle args) {
throw new UnsupportedOperationException("unimplemented mock method call");
}
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index 1831bcdf9df7..223bcc59039d 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -145,12 +145,23 @@ public class MockIContentProvider implements IContentProvider {
}
@Override
- public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
- throws RemoteException {
+ public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
+ @SuppressWarnings("deprecation")
+ public void canonicalizeAsync(String callingPkg, String featureId, Uri uri,
+ RemoteCallback remoteCallback) {
+ AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+ canonicalize(callingPkg, featureId, uri));
+ remoteCallback.sendResult(bundle);
+ });
+ }
+
+ @Override
public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
index a7e33b3d63b6..a63d58d5a0f6 100644
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ b/tests/net/common/java/android/net/NetworkScoreTest.kt
@@ -16,9 +16,7 @@
package android.net
-import android.net.NetworkScore.POLICY_DEFAULT_SUBSCRIPTION
-import android.net.NetworkScore.POLICY_IGNORE_ON_WIFI
-import android.net.NetworkScore.RANGE_MEDIUM
+import android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
@@ -34,30 +32,26 @@ private const val TEST_SCORE = 80
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkScoreTest {
- private fun makeScoreBuilder() = NetworkScore.Builder()
- .setLegacyScore(TEST_SCORE)
- .addPolicy(POLICY_IGNORE_ON_WIFI)
- .addPolicy(POLICY_DEFAULT_SUBSCRIPTION)
- .setExiting(false)
- .setEndToEndMetrics(NetworkScore.Metrics(145 /* latency */,
- 2500 /* downlinkBandwidth */, 1430 /* uplinkBandwidth */))
- .setRange(RANGE_MEDIUM)
- .setSignalStrength(400)
-
@Test
fun testParcelNetworkScore() {
val defaultCap = NetworkCapabilities()
- val legacyBuilder = NetworkScore.Builder().setLegacyScore(TEST_SCORE)
- assertEquals(TEST_SCORE, legacyBuilder.build().getLegacyScore())
- assertParcelSane(legacyBuilder.build(), 7)
+ val builder = NetworkScore.Builder().setLegacyScore(TEST_SCORE)
+ assertEquals(TEST_SCORE, builder.build().getLegacyScore())
+ assertParcelSane(builder.build(), 7)
- val builder = makeScoreBuilder()
+ builder.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+ .addPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION)
+ .setLinkLayerMetrics(NetworkScore.Metrics(44 /* latency */,
+ 380 /* downlinkBandwidth */, BANDWIDTH_UNKNOWN /* uplinkBandwidth */))
+ .setEndToEndMetrics(NetworkScore.Metrics(11 /* latency */,
+ BANDWIDTH_UNKNOWN /* downlinkBandwidth */, 100_000 /* uplinkBandwidth */))
+ .setRange(NetworkScore.RANGE_MEDIUM)
assertParcelSane(builder.build(), 7)
- builder.clearPolicy(POLICY_IGNORE_ON_WIFI)
+ builder.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
val ns = builder.build()
assertParcelSane(ns, 7)
- assertFalse(ns.hasPolicy(POLICY_IGNORE_ON_WIFI))
- assertTrue(ns.hasPolicy(POLICY_DEFAULT_SUBSCRIPTION))
+ assertFalse(ns.hasPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI))
+ assertTrue(ns.hasPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION))
val exitingNs = ns.withExiting(true)
assertNotEquals(ns.isExiting, exitingNs.isExiting)
@@ -79,10 +73,4 @@ class NetworkScoreTest {
assertTrue(builder1.build().equals(builder2.build()))
assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
}
-
- @Test
- fun testBuilderEquals() {
- val ns = makeScoreBuilder().build()
- assertEquals(ns, NetworkScore.Builder(ns).build())
- }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6d4a1b265171..4e75f2a273a9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2058,15 +2058,14 @@ public class ConnectivityServiceTest {
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // Bring up validated wifi.
+ // Bring up wifi with a score of 70.
// Cell is lingered because it would not satisfy any request, even if it validated.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true); // Score: 60
+ mWiFiNetworkAgent.adjustScore(50);
+ mWiFiNetworkAgent.connect(false); // Score: 70
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -5850,7 +5849,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- trustedCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
reset(mNetworkManagementService);
diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
index d2532c2ce3d3..86c91165f61b 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -16,18 +16,13 @@
package com.android.server.connectivity
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.LinkProperties
-import android.net.Network
-import android.net.NetworkAgentConfig
-import android.net.NetworkCapabilities
-import android.net.NetworkInfo
import android.net.NetworkRequest
-import android.net.NetworkScore
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import kotlin.test.assertEquals
import kotlin.test.assertNull
@@ -37,24 +32,9 @@ import kotlin.test.assertNull
class NetworkRankerTest {
private val ranker = NetworkRanker()
- private fun makeNai(satisfy: Boolean, score: Int) = object : NetworkAgentInfo(
- null /* messenger */,
- null /* asyncChannel*/,
- Network(100),
- NetworkInfo(TYPE_WIFI, 0 /* subtype */, "" /* typename */, "" /* subtypename */),
- LinkProperties(),
- NetworkCapabilities(),
- NetworkScore.Builder().setLegacyScore(score).build(),
- null /* context */,
- null /* handler */,
- NetworkAgentConfig(),
- null /* connectivityService */,
- null /* netd */,
- null /* dnsResolver */,
- null /* networkManagementService */,
- 0 /* factorySerialNumber */) {
- override fun satisfies(request: NetworkRequest?): Boolean = satisfy
- override fun getCurrentScore(): Int = score
+ private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also {
+ doReturn(satisfy).`when`(it).satisfies(any())
+ doReturn(score).`when`(it).currentScore
}
@Test
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
index 96619273af8d..6a5b0e1347b2 100755
--- a/tools/hiddenapi/merge_csv.py
+++ b/tools/hiddenapi/merge_csv.py
@@ -14,26 +14,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
-Merge mutliple CSV files, possibly with different columns, writing to stdout.
+Merge multiple CSV files, possibly with different columns.
"""
+import argparse
import csv
-import sys
+import io
-csv_readers = [
- csv.DictReader(open(csv_file, 'r'), delimiter=',', quotechar='|')
- for csv_file in sys.argv[1:]
-]
+from zipfile import ZipFile
+
+args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
+args_parser.add_argument('--header', help='Comma separated field names; '
+ 'if missing determines the header from input files.')
+args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
+args_parser.add_argument('--output', help='Output file for merged CSV.',
+ default='-', type=argparse.FileType('w'))
+args_parser.add_argument('files', nargs=argparse.REMAINDER)
+args = args_parser.parse_args()
+
+
+def dict_reader(input):
+ return csv.DictReader(input, delimiter=',', quotechar='|')
+
+
+if args.zip_input and len(args.files) > 0:
+ raise ValueError('Expecting either a single ZIP with CSV files'
+ ' or a list of CSV files as input; not both.')
+
+csv_readers = []
+if len(args.files) > 0:
+ for file in args.files:
+ csv_readers.append(dict_reader(open(file, 'r')))
+elif args.zip_input:
+ with ZipFile(args.zip_input) as zip:
+ for entry in zip.namelist():
+ if entry.endswith('.uau'):
+ csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
-# Build union of all columns from source files:
headers = set()
-for reader in csv_readers:
- headers = headers.union(reader.fieldnames)
+if args.header:
+ fieldnames = args.header.split(',')
+else:
+ # Build union of all columns from source files:
+ for reader in csv_readers:
+ headers = headers.union(reader.fieldnames)
+ fieldnames = sorted(headers)
# Concatenate all files to output:
-out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
- dialect='unix', fieldnames=sorted(headers))
-out.writeheader()
+writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
+ dialect='unix', fieldnames=fieldnames)
+writer.writeheader()
for reader in csv_readers:
for row in reader:
- out.writerow(row)
+ writer.writerow(row)
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 5c9fb4e86bc7..0c6cf1c170f5 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -89,6 +89,7 @@ java_library {
],
srcs: [
":framework-wifi-updatable-sources",
+ ":framework-wifi-util-lib-aidls",
],
// java_api_finder must accompany `srcs`
plugins: ["java_api_finder"],
diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java
index 2bbe7d2aa4ec..a831984f3968 100644
--- a/wifi/java/android/net/wifi/SoftApCapability.java
+++ b/wifi/java/android/net/wifi/SoftApCapability.java
@@ -16,7 +16,7 @@
package android.net.wifi;
-import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -47,7 +47,7 @@ public final class SoftApCapability implements Parcelable {
* {@link SoftApInfo#getFrequency} and {@link SoftApInfo#getBandwidth} to get
* driver channel selection result.
*/
- public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1 << 0;
+ public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1 << 0;
/**
* Support for client force disconnect.
@@ -59,7 +59,7 @@ public final class SoftApCapability implements Parcelable {
* Check feature support before invoking
* {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
*/
- public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
+ public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
/**
@@ -67,18 +67,18 @@ public final class SoftApCapability implements Parcelable {
*
* flag when {@link config_wifi_softap_sae_supported)} is true.
*/
- public static final int SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
+ public static final long SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
+ @LongDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
SOFTAP_FEATURE_ACS_OFFLOAD,
SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
SOFTAP_FEATURE_WPA3_SAE,
})
public @interface HotspotFeatures {}
- private @HotspotFeatures int mSupportedFeatures = 0;
+ private @HotspotFeatures long mSupportedFeatures = 0;
private int mMaximumSupportedClientNumber;
@@ -104,7 +104,7 @@ public final class SoftApCapability implements Parcelable {
*
* @param feature one of feature from {@link HotspotFeatures}
*/
- public boolean isFeatureSupported(@HotspotFeatures int feature) {
+ public boolean isFeatureSupported(@HotspotFeatures long feature) {
return (mSupportedFeatures & feature) == feature;
}
@@ -125,7 +125,7 @@ public final class SoftApCapability implements Parcelable {
* @param features One or combination of the feature from {@link @HotspotFeatures}.
* @hide
*/
- public SoftApCapability(@HotspotFeatures int features) {
+ public SoftApCapability(@HotspotFeatures long features) {
mSupportedFeatures = features;
}
@@ -138,7 +138,7 @@ public final class SoftApCapability implements Parcelable {
@Override
/** Implement the Parcelable interface */
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mSupportedFeatures);
+ dest.writeLong(mSupportedFeatures);
dest.writeInt(mMaximumSupportedClientNumber);
}
@@ -146,7 +146,7 @@ public final class SoftApCapability implements Parcelable {
/** Implement the Parcelable interface */
public static final Creator<SoftApCapability> CREATOR = new Creator<SoftApCapability>() {
public SoftApCapability createFromParcel(Parcel in) {
- int supportedFeatures = in.readInt();
+ long supportedFeatures = in.readLong();
SoftApCapability capability = new SoftApCapability(supportedFeatures);
capability.mMaximumSupportedClientNumber = in.readInt();
return capability;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e1450cb794f6..1a12af341910 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2167,6 +2167,7 @@ public class WifiConfiguration implements Parcelable {
sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
+ .append(" HOME-PROVIDER-NETWORK: ").append(this.isHomeProviderNetwork)
.append(" PRIO: ").append(this.priority)
.append(" HIDDEN: ").append(this.hiddenSSID)
.append(" PMF: ").append(this.requirePmf)
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
index 3215246a9c1f..7d24142ba135 100644
--- a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -25,7 +25,6 @@ import android.annotation.SystemService;
import android.app.AlarmManager;
import android.content.Context;
import android.net.wifi.SoftApInfo;
-import android.net.wifi.WifiAnnotations;
import android.net.wifi.WifiScanner;
import android.os.Binder;
import android.os.Handler;
@@ -245,7 +244,7 @@ public class WifiNl80211Manager {
* indication that the SoftAp is not enabled.
* @param bandwidth The new bandwidth of the SoftAp.
*/
- void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth);
+ void onSoftApChannelSwitched(int frequencyMhz, int bandwidth);
}
/**
@@ -383,7 +382,7 @@ public class WifiNl80211Manager {
toFrameworkBandwidth(bandwidth)));
}
- private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
+ private int toFrameworkBandwidth(int bandwidth) {
switch(bandwidth) {
case IApInterfaceEventCallback.BANDWIDTH_INVALID:
return SoftApInfo.CHANNEL_WIDTH_INVALID;
@@ -856,7 +855,7 @@ public class WifiNl80211Manager {
/**
* Return scan type for the parcelable {@link SingleScanSettings}
*/
- private static int getScanType(@WifiAnnotations.ScanType int scanType) {
+ private static int getScanType(int scanType) {
switch (scanType) {
case WifiScanner.SCAN_TYPE_LOW_LATENCY:
return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN;
@@ -891,7 +890,7 @@ public class WifiNl80211Manager {
* @return Returns true on success, false on failure (e.g. when called before the interface
* has been set up).
*/
- public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
+ public boolean startScan(@NonNull String ifaceName, int scanType,
@Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
@@ -1047,7 +1046,7 @@ public class WifiNl80211Manager {
* @return frequencies vector of valid frequencies (MHz), or an empty array for error.
* @throws IllegalArgumentException if band is not recognized.
*/
- public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) {
+ public @NonNull int[] getChannelsMhzForBand(int band) {
if (mWificond == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return new int[0];
@@ -1226,7 +1225,7 @@ public class WifiNl80211Manager {
*/
public static class OemSecurityType {
/** The protocol defined in {@link android.net.wifi.WifiAnnotations.Protocol}. */
- public final @WifiAnnotations.Protocol int protocol;
+ public final int protocol;
/**
* Supported key management types defined
* in {@link android.net.wifi.WifiAnnotations.KeyMgmt}.
@@ -1238,7 +1237,7 @@ public class WifiNl80211Manager {
*/
@NonNull public final List<Integer> pairwiseCipher;
/** The group cipher type defined in {@link android.net.wifi.WifiAnnotations.Cipher}. */
- public final @WifiAnnotations.Cipher int groupCipher;
+ public final int groupCipher;
/**
* Default constructor for OemSecurityType
*
@@ -1252,10 +1251,10 @@ public class WifiNl80211Manager {
* in {@link android.net.wifi.WifiAnnotations.Cipher}.
*/
public OemSecurityType(
- @WifiAnnotations.Protocol int protocol,
+ int protocol,
@NonNull List<Integer> keyManagement,
@NonNull List<Integer> pairwiseCipher,
- @WifiAnnotations.Cipher int groupCipher) {
+ int groupCipher) {
this.protocol = protocol;
this.keyManagement = (keyManagement != null)
? keyManagement : new ArrayList<Integer>();
diff --git a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java
index ef476ebc2667..73b501a4d8f2 100644
--- a/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApCapabilityTest.java
@@ -35,7 +35,7 @@ public class SoftApCapabilityTest {
*/
@Test
public void testCopyOperator() throws Exception {
- int testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+ long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
| SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
SoftApCapability capability = new SoftApCapability(testSoftApFeature);
capability.setMaxSupportedClients(10);
@@ -51,7 +51,7 @@ public class SoftApCapabilityTest {
*/
@Test
public void testParcelOperation() throws Exception {
- int testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+ long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
| SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
SoftApCapability capability = new SoftApCapability(testSoftApFeature);
capability.setMaxSupportedClients(10);